@jsenv/navi 0.12.30 → 0.12.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.
- package/dist/jsenv_navi.js +2066 -2062
- package/dist/jsenv_navi.js.map +86 -88
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { installImportMetaCss } from "./jsenv_navi_side_effects.js";
|
|
2
|
-
import { createIterableWeakSet, createPubSub, createValueEffect, createStyleController, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, allowWheelThrough, resolveCSSColor, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, activeElementSignal, canInterceptKeys, createGroupTransitionController, getElementSignature, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, stringifyStyle, mergeOneStyle, mergeTwoStyles, normalizeStyles, resolveCSSSize, findBefore, findAfter, hasCSSSizeUnit,
|
|
2
|
+
import { createIterableWeakSet, createPubSub, createValueEffect, createStyleController, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, allowWheelThrough, resolveCSSColor, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, activeElementSignal, canInterceptKeys, createGroupTransitionController, getElementSignature, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, stringifyStyle, mergeOneStyle, mergeTwoStyles, normalizeStyles, resolveCSSSize, findBefore, findAfter, hasCSSSizeUnit, pickLightOrDark, resolveColorLuminance, initFocusGroup, elementIsFocusable, dragAfterThreshold, getScrollContainer, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement } from "@jsenv/dom";
|
|
3
3
|
import { prefixFirstAndIndentRemainingLines } from "@jsenv/humanize";
|
|
4
4
|
import { effect, signal, computed, batch, useSignal } from "@preact/signals";
|
|
5
|
-
import { useEffect, useRef, useCallback, useContext, useState, useLayoutEffect, useMemo,
|
|
5
|
+
import { useEffect, useRef, useCallback, useContext, useState, useLayoutEffect, useMemo, useImperativeHandle, useErrorBoundary, useId } from "preact/hooks";
|
|
6
6
|
import { createContext, toChildArray, createRef, cloneElement } from "preact";
|
|
7
7
|
import { jsxs, jsx, Fragment } from "preact/jsx-runtime";
|
|
8
8
|
import { createPortal, forwardRef } from "preact/compat";
|
|
@@ -7690,7 +7690,9 @@ const createRoute = (urlPatternInput) => {
|
|
|
7690
7690
|
// always remove the wildcard part for URL building since it's optional
|
|
7691
7691
|
if (relativeUrl.endsWith("/*?")) {
|
|
7692
7692
|
// Always remove the optional wildcard part for URL building
|
|
7693
|
-
relativeUrl = relativeUrl.
|
|
7693
|
+
relativeUrl = relativeUrl.slice(0, -"/*?".length);
|
|
7694
|
+
} else if (relativeUrl.endsWith("{/}?*")) {
|
|
7695
|
+
relativeUrl = relativeUrl.slice(0, -"{/}?*".length);
|
|
7694
7696
|
} else {
|
|
7695
7697
|
// For required wildcards (/*) or other patterns, replace normally
|
|
7696
7698
|
let wildcardIndex = 0;
|
|
@@ -13851,7 +13853,7 @@ const TextBasic = ({
|
|
|
13851
13853
|
as: "span",
|
|
13852
13854
|
baseClassName: "navi_text",
|
|
13853
13855
|
...rest,
|
|
13854
|
-
children: rest.as === "pre" ? children : applySpacingOnTextChildren(children, spacing)
|
|
13856
|
+
children: rest.as === "pre" || rest.box || rest.column || rest.row ? children : applySpacingOnTextChildren(children, spacing)
|
|
13855
13857
|
});
|
|
13856
13858
|
};
|
|
13857
13859
|
|
|
@@ -15623,559 +15625,557 @@ const RouteLink = ({
|
|
|
15623
15625
|
};
|
|
15624
15626
|
|
|
15625
15627
|
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
15626
|
-
.
|
|
15627
|
-
|
|
15628
|
-
|
|
15629
|
-
|
|
15630
|
-
|
|
15631
|
-
margin-bottom: 20px;
|
|
15632
|
-
}
|
|
15633
|
-
`;
|
|
15634
|
-
const renderIdleDefault = () => null;
|
|
15635
|
-
const renderLoadingDefault = () => null;
|
|
15636
|
-
const renderAbortedDefault = () => null;
|
|
15637
|
-
const renderErrorDefault = error => {
|
|
15638
|
-
let routeErrorText = error && error.message ? error.message : error;
|
|
15639
|
-
return jsxs("p", {
|
|
15640
|
-
className: "action_error",
|
|
15641
|
-
children: ["An error occured: ", routeErrorText]
|
|
15642
|
-
});
|
|
15643
|
-
};
|
|
15644
|
-
const renderCompletedDefault = () => null;
|
|
15645
|
-
const ActionRenderer = ({
|
|
15646
|
-
action,
|
|
15647
|
-
children,
|
|
15648
|
-
disabled
|
|
15649
|
-
}) => {
|
|
15650
|
-
const {
|
|
15651
|
-
idle: renderIdle = renderIdleDefault,
|
|
15652
|
-
loading: renderLoading = renderLoadingDefault,
|
|
15653
|
-
aborted: renderAborted = renderAbortedDefault,
|
|
15654
|
-
error: renderError = renderErrorDefault,
|
|
15655
|
-
completed: renderCompleted,
|
|
15656
|
-
always: renderAlways
|
|
15657
|
-
} = typeof children === "function" ? {
|
|
15658
|
-
completed: children
|
|
15659
|
-
} : children || {};
|
|
15660
|
-
if (disabled) {
|
|
15661
|
-
return null;
|
|
15628
|
+
.navi_tablist {
|
|
15629
|
+
display: flex;
|
|
15630
|
+
justify-content: space-between;
|
|
15631
|
+
overflow-x: auto;
|
|
15632
|
+
overflow-y: hidden;
|
|
15662
15633
|
}
|
|
15663
|
-
|
|
15664
|
-
|
|
15634
|
+
|
|
15635
|
+
.navi_tablist > ul {
|
|
15636
|
+
display: flex;
|
|
15637
|
+
margin: 0;
|
|
15638
|
+
padding: 0;
|
|
15639
|
+
align-items: center;
|
|
15640
|
+
gap: 0.5rem;
|
|
15641
|
+
list-style: none;
|
|
15665
15642
|
}
|
|
15666
|
-
const {
|
|
15667
|
-
idle,
|
|
15668
|
-
loading,
|
|
15669
|
-
aborted,
|
|
15670
|
-
error,
|
|
15671
|
-
data
|
|
15672
|
-
} = useActionStatus(action);
|
|
15673
|
-
const UIRenderedPromise = useUIRenderedPromise(action);
|
|
15674
|
-
const [errorBoundary, resetErrorBoundary] = useErrorBoundary();
|
|
15675
15643
|
|
|
15676
|
-
|
|
15677
|
-
|
|
15678
|
-
|
|
15679
|
-
|
|
15680
|
-
if (action) {
|
|
15681
|
-
const {
|
|
15682
|
-
ui
|
|
15683
|
-
} = getActionPrivateProperties(action);
|
|
15684
|
-
ui.hasRenderers = true;
|
|
15685
|
-
}
|
|
15686
|
-
}, [action]);
|
|
15687
|
-
useLayoutEffect(() => {
|
|
15688
|
-
resetErrorBoundary();
|
|
15689
|
-
}, [action, loading, idle, resetErrorBoundary]);
|
|
15690
|
-
useLayoutEffect(() => {
|
|
15691
|
-
UIRenderedPromise.resolve();
|
|
15692
|
-
return () => {
|
|
15693
|
-
actionUIRenderedPromiseWeakMap.delete(action);
|
|
15694
|
-
};
|
|
15695
|
-
}, [action]);
|
|
15644
|
+
.navi_tablist > ul > li {
|
|
15645
|
+
position: relative;
|
|
15646
|
+
display: inline-flex;
|
|
15647
|
+
}
|
|
15696
15648
|
|
|
15697
|
-
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15701
|
-
loading,
|
|
15702
|
-
aborted,
|
|
15703
|
-
error,
|
|
15704
|
-
data
|
|
15705
|
-
});
|
|
15649
|
+
.navi_tab {
|
|
15650
|
+
display: flex;
|
|
15651
|
+
flex-direction: column;
|
|
15652
|
+
white-space: nowrap;
|
|
15706
15653
|
}
|
|
15707
|
-
|
|
15708
|
-
|
|
15654
|
+
|
|
15655
|
+
.navi_tab_content {
|
|
15656
|
+
display: flex;
|
|
15657
|
+
padding: 0 0.5rem;
|
|
15658
|
+
text-decoration: none;
|
|
15659
|
+
line-height: 30px;
|
|
15660
|
+
border-radius: 6px;
|
|
15661
|
+
transition: background 0.12s ease-out;
|
|
15709
15662
|
}
|
|
15710
|
-
|
|
15711
|
-
|
|
15663
|
+
|
|
15664
|
+
.navi_tab:hover .navi_tab_content {
|
|
15665
|
+
color: #010409;
|
|
15666
|
+
background: #dae0e7;
|
|
15712
15667
|
}
|
|
15713
|
-
|
|
15714
|
-
|
|
15668
|
+
|
|
15669
|
+
.navi_tab .active_marker {
|
|
15670
|
+
z-index: 1;
|
|
15671
|
+
display: flex;
|
|
15672
|
+
width: 100%;
|
|
15673
|
+
height: 2px;
|
|
15674
|
+
margin-top: 5px;
|
|
15675
|
+
background: transparent;
|
|
15676
|
+
border-radius: 0.1px;
|
|
15715
15677
|
}
|
|
15716
|
-
|
|
15717
|
-
|
|
15678
|
+
|
|
15679
|
+
/* Hidden bold clone to reserve space for bold width without affecting height */
|
|
15680
|
+
.navi_tab_content_bold_clone {
|
|
15681
|
+
display: block; /* in-flow so it contributes to width */
|
|
15682
|
+
height: 0; /* zero height so it doesn't change layout height */
|
|
15683
|
+
font-weight: 600; /* force bold to compute max width */
|
|
15684
|
+
visibility: hidden; /* not visible */
|
|
15685
|
+
pointer-events: none; /* inert */
|
|
15686
|
+
overflow: hidden; /* avoid any accidental height */
|
|
15718
15687
|
}
|
|
15719
|
-
|
|
15720
|
-
|
|
15721
|
-
|
|
15722
|
-
} else {
|
|
15723
|
-
const {
|
|
15724
|
-
ui
|
|
15725
|
-
} = getActionPrivateProperties(action);
|
|
15726
|
-
if (ui.renderCompleted) {
|
|
15727
|
-
renderCompletedSafe = ui.renderCompleted;
|
|
15728
|
-
} else {
|
|
15729
|
-
renderCompletedSafe = renderCompletedDefault;
|
|
15730
|
-
}
|
|
15688
|
+
|
|
15689
|
+
.navi_tab[aria-selected="true"] .active_marker {
|
|
15690
|
+
background: rgb(205, 52, 37);
|
|
15731
15691
|
}
|
|
15732
|
-
|
|
15733
|
-
|
|
15734
|
-
|
|
15735
|
-
}
|
|
15736
|
-
return renderLoading(action);
|
|
15692
|
+
|
|
15693
|
+
.navi_tab[aria-selected="true"] .navi_tab_content {
|
|
15694
|
+
font-weight: 600;
|
|
15737
15695
|
}
|
|
15738
|
-
|
|
15696
|
+
`;
|
|
15697
|
+
const TabList = ({
|
|
15698
|
+
children,
|
|
15699
|
+
...props
|
|
15700
|
+
}) => {
|
|
15701
|
+
return jsx(Box, {
|
|
15702
|
+
as: "nav",
|
|
15703
|
+
baseClassName: "navi_tablist",
|
|
15704
|
+
role: "tablist",
|
|
15705
|
+
...props,
|
|
15706
|
+
children: jsx("ul", {
|
|
15707
|
+
role: "list",
|
|
15708
|
+
children: children.map(child => {
|
|
15709
|
+
return jsx("li", {
|
|
15710
|
+
children: child
|
|
15711
|
+
}, child.props.key);
|
|
15712
|
+
})
|
|
15713
|
+
})
|
|
15714
|
+
});
|
|
15739
15715
|
};
|
|
15740
|
-
const
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
|
|
15751
|
-
|
|
15752
|
-
|
|
15753
|
-
|
|
15716
|
+
const Tab = ({
|
|
15717
|
+
children,
|
|
15718
|
+
selected,
|
|
15719
|
+
...props
|
|
15720
|
+
}) => {
|
|
15721
|
+
return jsxs(Box, {
|
|
15722
|
+
baseClassName: "navi_tab",
|
|
15723
|
+
role: "tab",
|
|
15724
|
+
"aria-selected": selected ? "true" : "false",
|
|
15725
|
+
...props,
|
|
15726
|
+
children: [jsx("div", {
|
|
15727
|
+
className: "navi_tab_content",
|
|
15728
|
+
children: children
|
|
15729
|
+
}), jsx("div", {
|
|
15730
|
+
className: "navi_tab_content_bold_clone",
|
|
15731
|
+
"aria-hidden": "true",
|
|
15732
|
+
children: children
|
|
15733
|
+
}), jsx("span", {
|
|
15734
|
+
className: "active_marker"
|
|
15735
|
+
})]
|
|
15754
15736
|
});
|
|
15755
|
-
promise.resolve = resolve;
|
|
15756
|
-
actionUIRenderedPromiseWeakMap.set(action, promise);
|
|
15757
|
-
return promise;
|
|
15758
15737
|
};
|
|
15759
15738
|
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
useLayoutEffect(() => {
|
|
15765
|
-
if (!enabled) {
|
|
15766
|
-
return null;
|
|
15739
|
+
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
15740
|
+
@layer navi {
|
|
15741
|
+
label {
|
|
15742
|
+
cursor: pointer;
|
|
15767
15743
|
}
|
|
15768
|
-
const focusGroup = initFocusGroup(elementRef.current, {
|
|
15769
|
-
direction,
|
|
15770
|
-
skipTab,
|
|
15771
|
-
loop,
|
|
15772
|
-
name,
|
|
15773
|
-
});
|
|
15774
|
-
return focusGroup.cleanup;
|
|
15775
|
-
}, [direction, skipTab, loop, name]);
|
|
15776
|
-
};
|
|
15777
15744
|
|
|
15778
|
-
|
|
15779
|
-
|
|
15780
|
-
|
|
15781
|
-
|
|
15782
|
-
width: 1em;
|
|
15783
|
-
height: 1em;
|
|
15784
|
-
line-height: 1em;
|
|
15785
|
-
}
|
|
15786
|
-
.summary_marker_svg .arrow {
|
|
15787
|
-
animation-duration: 0.3s;
|
|
15788
|
-
animation-fill-mode: forwards;
|
|
15789
|
-
animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
15790
|
-
}
|
|
15791
|
-
.summary_marker_svg .arrow[data-animation-target="down"] {
|
|
15792
|
-
animation-name: morph-to-down;
|
|
15793
|
-
}
|
|
15794
|
-
@keyframes morph-to-down {
|
|
15795
|
-
from {
|
|
15796
|
-
d: path("${rightArrowPath}");
|
|
15797
|
-
}
|
|
15798
|
-
to {
|
|
15799
|
-
d: path("${downArrowPath}");
|
|
15800
|
-
}
|
|
15801
|
-
}
|
|
15802
|
-
.summary_marker_svg .arrow[data-animation-target="right"] {
|
|
15803
|
-
animation-name: morph-to-right;
|
|
15804
|
-
}
|
|
15805
|
-
@keyframes morph-to-right {
|
|
15806
|
-
from {
|
|
15807
|
-
d: path("${downArrowPath}");
|
|
15808
|
-
}
|
|
15809
|
-
to {
|
|
15810
|
-
d: path("${rightArrowPath}");
|
|
15745
|
+
label[data-readonly],
|
|
15746
|
+
label[data-disabled] {
|
|
15747
|
+
color: rgba(0, 0, 0, 0.5);
|
|
15748
|
+
cursor: default;
|
|
15811
15749
|
}
|
|
15812
15750
|
}
|
|
15751
|
+
`;
|
|
15752
|
+
const ReportReadOnlyOnLabelContext = createContext();
|
|
15753
|
+
const ReportDisabledOnLabelContext = createContext();
|
|
15754
|
+
const Label = props => {
|
|
15755
|
+
const {
|
|
15756
|
+
readOnly,
|
|
15757
|
+
disabled,
|
|
15758
|
+
children,
|
|
15759
|
+
...rest
|
|
15760
|
+
} = props;
|
|
15761
|
+
const [inputReadOnly, setInputReadOnly] = useState(false);
|
|
15762
|
+
const innerReadOnly = readOnly || inputReadOnly;
|
|
15763
|
+
const [inputDisabled, setInputDisabled] = useState(false);
|
|
15764
|
+
const innerDisabled = disabled || inputDisabled;
|
|
15765
|
+
return jsx(Box, {
|
|
15766
|
+
...rest,
|
|
15767
|
+
as: "label",
|
|
15768
|
+
basePseudoState: {
|
|
15769
|
+
readOnly: innerReadOnly,
|
|
15770
|
+
disabled: innerDisabled
|
|
15771
|
+
},
|
|
15772
|
+
children: jsx(ReportReadOnlyOnLabelContext.Provider, {
|
|
15773
|
+
value: setInputReadOnly,
|
|
15774
|
+
children: jsx(ReportDisabledOnLabelContext.Provider, {
|
|
15775
|
+
value: setInputDisabled,
|
|
15776
|
+
children: children
|
|
15777
|
+
})
|
|
15778
|
+
})
|
|
15779
|
+
});
|
|
15780
|
+
};
|
|
15813
15781
|
|
|
15814
|
-
|
|
15815
|
-
|
|
15816
|
-
|
|
15817
|
-
|
|
15818
|
-
|
|
15819
|
-
|
|
15820
|
-
|
|
15821
|
-
|
|
15782
|
+
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
15783
|
+
@layer navi {
|
|
15784
|
+
.navi_checkbox {
|
|
15785
|
+
--outline-offset: 1px;
|
|
15786
|
+
--outline-width: 2px;
|
|
15787
|
+
--border-width: 1px;
|
|
15788
|
+
--border-radius: 2px;
|
|
15789
|
+
--width: 13px;
|
|
15790
|
+
--height: 13px;
|
|
15791
|
+
|
|
15792
|
+
--outline-color: var(--navi-focus-outline-color);
|
|
15793
|
+
--loader-color: var(--navi-loader-color);
|
|
15794
|
+
--border-color: light-dark(#767676, #8e8e93);
|
|
15795
|
+
--background-color: white;
|
|
15796
|
+
--color: light-dark(#4476ff, #3b82f6);
|
|
15797
|
+
--checkmark-color-light: white;
|
|
15798
|
+
--checkmark-color-dark: rgb(55, 55, 55);
|
|
15799
|
+
--checkmark-color: var(--checkmark-color-light);
|
|
15800
|
+
|
|
15801
|
+
--color-mix-light: black;
|
|
15802
|
+
--color-mix-dark: white;
|
|
15803
|
+
--color-mix: var(--color-mix-light);
|
|
15804
|
+
|
|
15805
|
+
/* Hover */
|
|
15806
|
+
--border-color-hover: color-mix(in srgb, var(--border-color) 60%, black);
|
|
15807
|
+
--border-color-hover-checked: color-mix(
|
|
15808
|
+
in srgb,
|
|
15809
|
+
var(--color) 80%,
|
|
15810
|
+
var(--color-mix)
|
|
15811
|
+
);
|
|
15812
|
+
--background-color-hover-checked: color-mix(
|
|
15813
|
+
in srgb,
|
|
15814
|
+
var(--color) 80%,
|
|
15815
|
+
var(--color-mix)
|
|
15816
|
+
);
|
|
15817
|
+
/* Readonly */
|
|
15818
|
+
--border-color-readonly: color-mix(
|
|
15819
|
+
in srgb,
|
|
15820
|
+
var(--border-color) 30%,
|
|
15821
|
+
white
|
|
15822
|
+
);
|
|
15823
|
+
--border-color-readonly-checked: #d3d3d3;
|
|
15824
|
+
--background-color-readonly-checked: grey;
|
|
15825
|
+
--checkmark-color-readonly: #eeeeee;
|
|
15826
|
+
/* Disabled */
|
|
15827
|
+
--border-color-disabled: var(--border-color-readonly);
|
|
15828
|
+
--background-color-disabled: rgba(248, 248, 248, 0.7);
|
|
15829
|
+
--checkmark-color-disabled: #eeeeee;
|
|
15830
|
+
--border-color-disabled-checked: #d3d3d3;
|
|
15831
|
+
--background-color-disabled-checked: #d3d3d3;
|
|
15822
15832
|
}
|
|
15823
|
-
|
|
15824
|
-
|
|
15833
|
+
|
|
15834
|
+
.navi_checkbox[data-dark] {
|
|
15835
|
+
--color-mix: var(--color-mix-dark);
|
|
15836
|
+
--checkmark-color: var(--navi-checkmark-color-dark);
|
|
15825
15837
|
}
|
|
15826
15838
|
}
|
|
15827
15839
|
|
|
15828
|
-
|
|
15829
|
-
|
|
15830
|
-
|
|
15831
|
-
|
|
15832
|
-
|
|
15833
|
-
|
|
15834
|
-
|
|
15835
|
-
|
|
15836
|
-
|
|
15837
|
-
|
|
15838
|
-
|
|
15839
|
-
|
|
15840
|
-
|
|
15840
|
+
.navi_checkbox {
|
|
15841
|
+
position: relative;
|
|
15842
|
+
display: inline-flex;
|
|
15843
|
+
box-sizing: content-box;
|
|
15844
|
+
margin: 3px 3px 3px 4px;
|
|
15845
|
+
|
|
15846
|
+
--x-border-radius: var(--border-radius);
|
|
15847
|
+
--x-outline-offset: var(--outline-offset);
|
|
15848
|
+
--x-outline-width: var(--outline-width);
|
|
15849
|
+
--x-border-width: var(--border-width);
|
|
15850
|
+
--x-width: var(--width);
|
|
15851
|
+
--x-height: var(--height);
|
|
15852
|
+
--x-outline-color: var(--outline-color);
|
|
15853
|
+
--x-background-color: var(--background-color);
|
|
15854
|
+
--x-border-color: var(--border-color);
|
|
15855
|
+
--x-color: var(--color);
|
|
15856
|
+
--x-checkmark-color: var(--checkmark-color);
|
|
15841
15857
|
}
|
|
15842
|
-
.
|
|
15858
|
+
.navi_checkbox .navi_native_field {
|
|
15859
|
+
position: absolute;
|
|
15860
|
+
inset: 0;
|
|
15861
|
+
margin: 0;
|
|
15862
|
+
padding: 0;
|
|
15863
|
+
border: none;
|
|
15843
15864
|
opacity: 0;
|
|
15865
|
+
cursor: inherit;
|
|
15844
15866
|
}
|
|
15845
|
-
.
|
|
15846
|
-
|
|
15867
|
+
.navi_checkbox .navi_checkbox_field {
|
|
15868
|
+
display: inline-flex;
|
|
15869
|
+
box-sizing: border-box;
|
|
15870
|
+
width: var(--x-width);
|
|
15871
|
+
height: var(--x-height);
|
|
15872
|
+
background-color: var(--x-background-color);
|
|
15873
|
+
border-width: var(--x-border-width);
|
|
15874
|
+
border-style: solid;
|
|
15875
|
+
border-color: var(--x-border-color);
|
|
15876
|
+
border-radius: var(--x-border-radius);
|
|
15877
|
+
outline-width: var(--x-outline-width);
|
|
15878
|
+
outline-style: none;
|
|
15879
|
+
outline-color: var(--x-outline-color);
|
|
15880
|
+
outline-offset: var(--x-outline-offset);
|
|
15847
15881
|
}
|
|
15848
|
-
.
|
|
15849
|
-
|
|
15882
|
+
.navi_checkbox_marker {
|
|
15883
|
+
width: 100%;
|
|
15884
|
+
height: 100%;
|
|
15885
|
+
opacity: 0;
|
|
15886
|
+
stroke: var(--x-checkmark-color);
|
|
15887
|
+
transform: scale(0.5);
|
|
15888
|
+
transition: all 0.15s ease;
|
|
15889
|
+
pointer-events: none;
|
|
15850
15890
|
}
|
|
15851
|
-
.
|
|
15891
|
+
.navi_checkbox[data-checked] .navi_checkbox_marker {
|
|
15852
15892
|
opacity: 1;
|
|
15893
|
+
transform: scale(1);
|
|
15853
15894
|
}
|
|
15854
|
-
`;
|
|
15855
|
-
const SummaryMarker = ({
|
|
15856
|
-
open,
|
|
15857
|
-
loading
|
|
15858
|
-
}) => {
|
|
15859
|
-
const showLoading = useDebounceTrue(loading, 300);
|
|
15860
|
-
const mountedRef = useRef(false);
|
|
15861
|
-
const prevOpenRef = useRef(open);
|
|
15862
|
-
useLayoutEffect(() => {
|
|
15863
|
-
mountedRef.current = true;
|
|
15864
|
-
return () => {
|
|
15865
|
-
mountedRef.current = false;
|
|
15866
|
-
};
|
|
15867
|
-
}, []);
|
|
15868
|
-
const shouldAnimate = mountedRef.current && prevOpenRef.current !== open;
|
|
15869
|
-
prevOpenRef.current = open;
|
|
15870
|
-
return jsx("span", {
|
|
15871
|
-
className: "summary_marker",
|
|
15872
|
-
children: jsxs("svg", {
|
|
15873
|
-
className: "summary_marker_svg",
|
|
15874
|
-
viewBox: "0 -960 960 960",
|
|
15875
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
15876
|
-
"data-loading": open ? showLoading || undefined : undefined,
|
|
15877
|
-
children: [jsxs("g", {
|
|
15878
|
-
className: "loading_container",
|
|
15879
|
-
"transform-origin": "480px -480px",
|
|
15880
|
-
children: [jsx("circle", {
|
|
15881
|
-
className: "background_circle",
|
|
15882
|
-
cx: "480",
|
|
15883
|
-
cy: "-480",
|
|
15884
|
-
r: "320",
|
|
15885
|
-
stroke: "currentColor",
|
|
15886
|
-
fill: "none",
|
|
15887
|
-
strokeWidth: "60",
|
|
15888
|
-
opacity: "0.2"
|
|
15889
|
-
}), jsx("circle", {
|
|
15890
|
-
className: "foreground_circle",
|
|
15891
|
-
cx: "480",
|
|
15892
|
-
cy: "-480",
|
|
15893
|
-
r: "320",
|
|
15894
|
-
stroke: "currentColor",
|
|
15895
|
-
fill: "none",
|
|
15896
|
-
strokeWidth: "60",
|
|
15897
|
-
strokeLinecap: "round",
|
|
15898
|
-
strokeDasharray: "503 1507"
|
|
15899
|
-
})]
|
|
15900
|
-
}), jsx("g", {
|
|
15901
|
-
className: "arrow_container",
|
|
15902
|
-
"transform-origin": "480px -480px",
|
|
15903
|
-
children: jsx("path", {
|
|
15904
|
-
className: "arrow",
|
|
15905
|
-
fill: "currentColor",
|
|
15906
|
-
"data-animation-target": shouldAnimate ? open ? "down" : "right" : undefined,
|
|
15907
|
-
d: open ? downArrowPath : rightArrowPath
|
|
15908
|
-
})
|
|
15909
|
-
})]
|
|
15910
|
-
})
|
|
15911
|
-
});
|
|
15912
|
-
};
|
|
15913
15895
|
|
|
15914
|
-
|
|
15915
|
-
.
|
|
15916
|
-
|
|
15917
|
-
z-index: 1;
|
|
15918
|
-
display: flex;
|
|
15919
|
-
flex-shrink: 0;
|
|
15920
|
-
flex-direction: column;
|
|
15896
|
+
/* Focus */
|
|
15897
|
+
.navi_checkbox[data-focus-visible] .navi_checkbox_field {
|
|
15898
|
+
outline-style: solid;
|
|
15921
15899
|
}
|
|
15922
|
-
|
|
15923
|
-
.
|
|
15924
|
-
|
|
15925
|
-
flex-shrink: 0;
|
|
15926
|
-
flex-direction: column;
|
|
15927
|
-
cursor: pointer;
|
|
15928
|
-
user-select: none;
|
|
15900
|
+
/* Hover */
|
|
15901
|
+
.navi_checkbox[data-hover] {
|
|
15902
|
+
--x-border-color: var(--border-color-hover);
|
|
15929
15903
|
}
|
|
15930
|
-
.
|
|
15931
|
-
|
|
15932
|
-
|
|
15933
|
-
flex-direction: row;
|
|
15934
|
-
align-items: center;
|
|
15935
|
-
gap: 0.2em;
|
|
15904
|
+
.navi_checkbox[data-checked][data-hover] {
|
|
15905
|
+
--x-border-color: var(--border-color-hover-checked);
|
|
15906
|
+
--x-background-color: var(--background-color-hover-checked);
|
|
15936
15907
|
}
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
15941
|
-
align-items: center;
|
|
15942
|
-
gap: 0.2em;
|
|
15908
|
+
/* Checked */
|
|
15909
|
+
.navi_checkbox[data-checked] {
|
|
15910
|
+
--x-background-color: var(--x-color);
|
|
15911
|
+
--x-border-color: var(--x-color);
|
|
15943
15912
|
}
|
|
15944
|
-
|
|
15945
|
-
.
|
|
15946
|
-
|
|
15913
|
+
/* Readonly */
|
|
15914
|
+
.navi_checkbox[data-readonly],
|
|
15915
|
+
.navi_checkbox[data-readonly][data-hover] {
|
|
15916
|
+
--x-border-color: var(--border-color-readonly);
|
|
15917
|
+
--x-background-color: var(--background-color-readonly);
|
|
15918
|
+
}
|
|
15919
|
+
.navi_checkbox[data-readonly][data-checked] {
|
|
15920
|
+
--x-border-color: var(--border-color-readonly-checked);
|
|
15921
|
+
--x-background-color: var(--background-color-readonly-checked);
|
|
15922
|
+
--x-checkmark-color: var(--checkmark-color-readonly);
|
|
15923
|
+
}
|
|
15924
|
+
/* Disabled */
|
|
15925
|
+
.navi_checkbox[data-disabled] {
|
|
15926
|
+
--x-border-color: var(--border-color-disabled);
|
|
15927
|
+
--x-background-color: var(--background-color-disabled);
|
|
15928
|
+
}
|
|
15929
|
+
.navi_checkbox[data-disabled][data-checked] {
|
|
15930
|
+
--x-border-color: var(--border-color-disabled-checked);
|
|
15931
|
+
--x-background-color: var(--background-color-disabled-checked);
|
|
15932
|
+
--x-checkmark-color: var(--checkmark-color-disabled);
|
|
15947
15933
|
}
|
|
15948
15934
|
`;
|
|
15949
|
-
const
|
|
15950
|
-
return renderActionableComponent(props, ref);
|
|
15951
|
-
});
|
|
15952
|
-
const DetailsBasic = forwardRef((props, ref) => {
|
|
15935
|
+
const InputCheckbox = props => {
|
|
15953
15936
|
const {
|
|
15954
|
-
|
|
15955
|
-
label = "Summary",
|
|
15956
|
-
open,
|
|
15957
|
-
loading,
|
|
15958
|
-
className,
|
|
15959
|
-
focusGroup,
|
|
15960
|
-
focusGroupDirection,
|
|
15961
|
-
arrowKeyShortcuts = true,
|
|
15962
|
-
openKeyShortcut = "ArrowRight",
|
|
15963
|
-
closeKeyShortcut = "ArrowLeft",
|
|
15964
|
-
onToggle,
|
|
15965
|
-
children,
|
|
15966
|
-
...rest
|
|
15937
|
+
value = "on"
|
|
15967
15938
|
} = props;
|
|
15968
|
-
const
|
|
15969
|
-
|
|
15970
|
-
|
|
15971
|
-
|
|
15972
|
-
|
|
15973
|
-
|
|
15974
|
-
name: typeof focusGroup === "string" ? focusGroup : undefined,
|
|
15975
|
-
direction: focusGroupDirection
|
|
15939
|
+
const uiStateController = useUIStateController(props, "checkbox", {
|
|
15940
|
+
statePropName: "checked",
|
|
15941
|
+
defaultStatePropName: "defaultChecked",
|
|
15942
|
+
fallbackState: false,
|
|
15943
|
+
getStateFromProp: checked => checked ? value : undefined,
|
|
15944
|
+
getPropFromState: Boolean
|
|
15976
15945
|
});
|
|
15946
|
+
const uiState = useUIState(uiStateController);
|
|
15947
|
+
const checkbox = renderActionableComponent(props, {
|
|
15948
|
+
Basic: InputCheckboxBasic,
|
|
15949
|
+
WithAction: InputCheckboxWithAction,
|
|
15950
|
+
InsideForm: InputCheckboxInsideForm
|
|
15951
|
+
});
|
|
15952
|
+
return jsx(UIStateControllerContext.Provider, {
|
|
15953
|
+
value: uiStateController,
|
|
15954
|
+
children: jsx(UIStateContext.Provider, {
|
|
15955
|
+
value: uiState,
|
|
15956
|
+
children: checkbox
|
|
15957
|
+
})
|
|
15958
|
+
});
|
|
15959
|
+
};
|
|
15960
|
+
const CheckboxStyleCSSVars = {
|
|
15961
|
+
"outlineWidth": "--outline-width",
|
|
15962
|
+
"borderWidth": "--border-width",
|
|
15963
|
+
"borderRadius": "--border-radius",
|
|
15964
|
+
"backgroundColor": "--background-color",
|
|
15965
|
+
"borderColor": "--border-color",
|
|
15966
|
+
"color": "--color",
|
|
15967
|
+
":hover": {
|
|
15968
|
+
backgroundColor: "--background-color-hover",
|
|
15969
|
+
borderColor: "--border-color-hover",
|
|
15970
|
+
color: "--color-hover"
|
|
15971
|
+
},
|
|
15972
|
+
":active": {
|
|
15973
|
+
borderColor: "--border-color-active"
|
|
15974
|
+
},
|
|
15975
|
+
":read-only": {
|
|
15976
|
+
backgroundColor: "--background-color-readonly",
|
|
15977
|
+
borderColor: "--border-color-readonly",
|
|
15978
|
+
color: "--color-readonly"
|
|
15979
|
+
},
|
|
15980
|
+
":disabled": {
|
|
15981
|
+
backgroundColor: "--background-color-disabled",
|
|
15982
|
+
borderColor: "--border-color-disabled",
|
|
15983
|
+
color: "--color-disabled"
|
|
15984
|
+
}
|
|
15985
|
+
};
|
|
15986
|
+
const CheckboxPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":checked", ":-navi-loading"];
|
|
15987
|
+
const CheckboxPseudoElements = ["::-navi-loader", "::-navi-checkmark"];
|
|
15988
|
+
const InputCheckboxBasic = props => {
|
|
15989
|
+
const contextFieldName = useContext(FieldNameContext);
|
|
15990
|
+
const contextReadOnly = useContext(ReadOnlyContext);
|
|
15991
|
+
const contextDisabled = useContext(DisabledContext);
|
|
15992
|
+
const contextRequired = useContext(RequiredContext);
|
|
15993
|
+
const contextLoading = useContext(LoadingContext);
|
|
15994
|
+
const loadingElement = useContext(LoadingElementContext);
|
|
15995
|
+
const uiStateController = useContext(UIStateControllerContext);
|
|
15996
|
+
const uiState = useContext(UIStateContext);
|
|
15997
|
+
const reportReadOnlyOnLabel = useContext(ReportReadOnlyOnLabelContext);
|
|
15998
|
+
const reportDisabledOnLabel = useContext(ReportDisabledOnLabelContext);
|
|
15999
|
+
const {
|
|
16000
|
+
/* eslint-disable no-unused-vars */
|
|
16001
|
+
type,
|
|
16002
|
+
defaultChecked,
|
|
16003
|
+
/* eslint-enable no-unused-vars */
|
|
15977
16004
|
|
|
15978
|
-
|
|
15979
|
-
|
|
15980
|
-
|
|
15981
|
-
|
|
15982
|
-
|
|
15983
|
-
|
|
15984
|
-
|
|
15985
|
-
|
|
15986
|
-
|
|
15987
|
-
|
|
15988
|
-
|
|
15989
|
-
|
|
15990
|
-
|
|
15991
|
-
|
|
15992
|
-
|
|
15993
|
-
const
|
|
15994
|
-
|
|
15995
|
-
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
|
|
16000
|
-
|
|
16001
|
-
|
|
16002
|
-
|
|
16003
|
-
|
|
16004
|
-
details.open = true;
|
|
16005
|
-
return;
|
|
16006
|
-
}
|
|
16007
|
-
const summary = summaryRef.current;
|
|
16008
|
-
const firstFocusableElementInDetails = findAfter(summary, elementIsFocusable, {
|
|
16009
|
-
root: details
|
|
16010
|
-
});
|
|
16011
|
-
if (!firstFocusableElementInDetails) {
|
|
16012
|
-
return;
|
|
16013
|
-
}
|
|
16005
|
+
name,
|
|
16006
|
+
readOnly,
|
|
16007
|
+
disabled,
|
|
16008
|
+
required,
|
|
16009
|
+
loading,
|
|
16010
|
+
autoFocus,
|
|
16011
|
+
constraints = [],
|
|
16012
|
+
onClick,
|
|
16013
|
+
onInput,
|
|
16014
|
+
color,
|
|
16015
|
+
...rest
|
|
16016
|
+
} = props;
|
|
16017
|
+
const defaultRef = useRef();
|
|
16018
|
+
const ref = props.ref || defaultRef;
|
|
16019
|
+
const innerName = name || contextFieldName;
|
|
16020
|
+
const innerDisabled = disabled || contextDisabled;
|
|
16021
|
+
const innerRequired = required || contextRequired;
|
|
16022
|
+
const innerLoading = loading || contextLoading && loadingElement === ref.current;
|
|
16023
|
+
const innerReadOnly = readOnly || contextReadOnly || innerLoading || uiStateController.readOnly;
|
|
16024
|
+
reportReadOnlyOnLabel?.(innerReadOnly);
|
|
16025
|
+
reportDisabledOnLabel?.(innerDisabled);
|
|
16026
|
+
useAutoFocus(ref, autoFocus);
|
|
16027
|
+
useConstraints(ref, constraints);
|
|
16028
|
+
const checked = Boolean(uiState);
|
|
16029
|
+
const innerOnClick = useStableCallback(e => {
|
|
16030
|
+
if (innerReadOnly) {
|
|
16014
16031
|
e.preventDefault();
|
|
16015
|
-
firstFocusableElementInDetails.focus();
|
|
16016
16032
|
}
|
|
16017
|
-
|
|
16018
|
-
|
|
16019
|
-
|
|
16020
|
-
|
|
16021
|
-
|
|
16022
|
-
|
|
16033
|
+
onClick?.(e);
|
|
16034
|
+
});
|
|
16035
|
+
const innerOnInput = useStableCallback(e => {
|
|
16036
|
+
const checkbox = e.target;
|
|
16037
|
+
const checkboxIsChecked = checkbox.checked;
|
|
16038
|
+
uiStateController.setUIState(checkboxIsChecked, e);
|
|
16039
|
+
onInput?.(e);
|
|
16040
|
+
});
|
|
16041
|
+
const renderCheckbox = checkboxProps => jsx(Box, {
|
|
16042
|
+
...checkboxProps,
|
|
16043
|
+
as: "input",
|
|
16044
|
+
ref: ref,
|
|
16045
|
+
type: "checkbox",
|
|
16046
|
+
name: innerName,
|
|
16047
|
+
checked: checked,
|
|
16048
|
+
required: innerRequired,
|
|
16049
|
+
baseClassName: "navi_native_field",
|
|
16050
|
+
"data-callout-arrow-x": "center",
|
|
16051
|
+
onClick: innerOnClick,
|
|
16052
|
+
onInput: innerOnInput,
|
|
16053
|
+
onresetuistate: e => {
|
|
16054
|
+
uiStateController.resetUIState(e);
|
|
16023
16055
|
},
|
|
16024
|
-
|
|
16025
|
-
|
|
16026
|
-
const summary = summaryRef.current;
|
|
16027
|
-
if (document.activeElement === summary) {
|
|
16028
|
-
e.preventDefault();
|
|
16029
|
-
summary.focus();
|
|
16030
|
-
details.open = false;
|
|
16031
|
-
} else {
|
|
16032
|
-
e.preventDefault();
|
|
16033
|
-
summary.focus();
|
|
16034
|
-
}
|
|
16056
|
+
onsetuistate: e => {
|
|
16057
|
+
uiStateController.setUIState(e.detail.value, e);
|
|
16035
16058
|
}
|
|
16036
|
-
}
|
|
16037
|
-
const
|
|
16038
|
-
|
|
16039
|
-
|
|
16040
|
-
|
|
16041
|
-
|
|
16059
|
+
});
|
|
16060
|
+
const renderCheckboxMemoized = useCallback(renderCheckbox, [innerName, checked, innerRequired]);
|
|
16061
|
+
useLayoutEffect(() => {
|
|
16062
|
+
const naviCheckbox = ref.current;
|
|
16063
|
+
const lightColor = "var(--checkmark-color-light)";
|
|
16064
|
+
const darkColor = "var(--checkmark-color-dark)";
|
|
16065
|
+
const colorPicked = pickLightOrDark("var(--color)", lightColor, darkColor, naviCheckbox);
|
|
16066
|
+
if (colorPicked === lightColor) {
|
|
16067
|
+
naviCheckbox.removeAttribute("data-dark");
|
|
16068
|
+
} else {
|
|
16069
|
+
naviCheckbox.setAttribute("data-dark", "");
|
|
16070
|
+
}
|
|
16071
|
+
}, [color]);
|
|
16072
|
+
return jsxs(Box, {
|
|
16073
|
+
as: "span",
|
|
16042
16074
|
...rest,
|
|
16043
|
-
ref:
|
|
16044
|
-
|
|
16045
|
-
|
|
16046
|
-
|
|
16047
|
-
|
|
16048
|
-
|
|
16049
|
-
|
|
16050
|
-
|
|
16051
|
-
|
|
16052
|
-
|
|
16053
|
-
innerOpenSetter(false);
|
|
16054
|
-
setNavState(undefined);
|
|
16055
|
-
}
|
|
16056
|
-
}
|
|
16057
|
-
onToggle?.(e);
|
|
16075
|
+
ref: ref,
|
|
16076
|
+
baseClassName: "navi_checkbox",
|
|
16077
|
+
pseudoStateSelector: ".navi_native_field",
|
|
16078
|
+
styleCSSVars: CheckboxStyleCSSVars,
|
|
16079
|
+
pseudoClasses: CheckboxPseudoClasses,
|
|
16080
|
+
pseudoElements: CheckboxPseudoElements,
|
|
16081
|
+
basePseudoState: {
|
|
16082
|
+
":read-only": innerReadOnly,
|
|
16083
|
+
":disabled": innerDisabled,
|
|
16084
|
+
":-navi-loading": innerLoading
|
|
16058
16085
|
},
|
|
16059
|
-
|
|
16060
|
-
|
|
16061
|
-
|
|
16062
|
-
|
|
16063
|
-
|
|
16064
|
-
|
|
16065
|
-
|
|
16066
|
-
|
|
16067
|
-
|
|
16068
|
-
|
|
16069
|
-
|
|
16070
|
-
|
|
16086
|
+
color: color,
|
|
16087
|
+
hasChildFunction: true,
|
|
16088
|
+
children: [jsx(LoaderBackground, {
|
|
16089
|
+
loading: innerLoading,
|
|
16090
|
+
inset: -1,
|
|
16091
|
+
color: "var(--loader-color)"
|
|
16092
|
+
}), renderCheckboxMemoized, jsx("div", {
|
|
16093
|
+
className: "navi_checkbox_field",
|
|
16094
|
+
children: jsx("svg", {
|
|
16095
|
+
viewBox: "0 0 12 12",
|
|
16096
|
+
"aria-hidden": "true",
|
|
16097
|
+
className: "navi_checkbox_marker",
|
|
16098
|
+
children: jsx("path", {
|
|
16099
|
+
d: "M10.5 2L4.5 9L1.5 5.5",
|
|
16100
|
+
fill: "none",
|
|
16101
|
+
strokeWidth: "2"
|
|
16102
|
+
})
|
|
16071
16103
|
})
|
|
16072
|
-
})
|
|
16104
|
+
})]
|
|
16073
16105
|
});
|
|
16074
|
-
}
|
|
16075
|
-
|
|
16106
|
+
};
|
|
16107
|
+
const InputCheckboxWithAction = props => {
|
|
16108
|
+
const uiStateController = useContext(UIStateControllerContext);
|
|
16109
|
+
const uiState = useContext(UIStateContext);
|
|
16076
16110
|
const {
|
|
16077
16111
|
action,
|
|
16078
|
-
|
|
16079
|
-
|
|
16112
|
+
onCancel,
|
|
16113
|
+
onChange,
|
|
16114
|
+
actionErrorEffect,
|
|
16080
16115
|
onActionPrevented,
|
|
16081
16116
|
onActionStart,
|
|
16117
|
+
onActionAbort,
|
|
16082
16118
|
onActionError,
|
|
16083
16119
|
onActionEnd,
|
|
16084
|
-
|
|
16120
|
+
loading,
|
|
16085
16121
|
...rest
|
|
16086
16122
|
} = props;
|
|
16087
|
-
const
|
|
16088
|
-
|
|
16089
|
-
const
|
|
16123
|
+
const defaultRef = useRef();
|
|
16124
|
+
const ref = props.ref || defaultRef;
|
|
16125
|
+
const [actionBoundToUIState] = useActionBoundToOneParam(action, uiState);
|
|
16090
16126
|
const {
|
|
16091
16127
|
loading: actionLoading
|
|
16092
|
-
} = useActionStatus(
|
|
16093
|
-
const executeAction = useExecuteAction(
|
|
16094
|
-
|
|
16095
|
-
errorEffect: "none"
|
|
16128
|
+
} = useActionStatus(actionBoundToUIState);
|
|
16129
|
+
const executeAction = useExecuteAction(ref, {
|
|
16130
|
+
errorEffect: actionErrorEffect
|
|
16096
16131
|
});
|
|
16097
|
-
|
|
16098
|
-
|
|
16099
|
-
|
|
16100
|
-
|
|
16132
|
+
|
|
16133
|
+
// In this situation updating the ui state === calling associated action
|
|
16134
|
+
// so cance/abort/error have to revert the ui state to the one before user interaction
|
|
16135
|
+
// to show back the real state of the checkbox (not the one user tried to set)
|
|
16136
|
+
useActionEvents(ref, {
|
|
16137
|
+
onCancel: (e, reason) => {
|
|
16138
|
+
if (reason === "blur_invalid") {
|
|
16139
|
+
return;
|
|
16140
|
+
}
|
|
16141
|
+
uiStateController.resetUIState(e);
|
|
16142
|
+
onCancel?.(e, reason);
|
|
16101
16143
|
},
|
|
16144
|
+
onPrevented: onActionPrevented,
|
|
16145
|
+
onAction: executeAction,
|
|
16102
16146
|
onStart: onActionStart,
|
|
16103
|
-
|
|
16104
|
-
|
|
16147
|
+
onAbort: e => {
|
|
16148
|
+
uiStateController.resetUIState(e);
|
|
16149
|
+
onActionAbort?.(e);
|
|
16150
|
+
},
|
|
16151
|
+
onError: e => {
|
|
16152
|
+
uiStateController.resetUIState(e);
|
|
16153
|
+
onActionError?.(e);
|
|
16154
|
+
},
|
|
16155
|
+
onEnd: e => {
|
|
16156
|
+
onActionEnd?.(e);
|
|
16157
|
+
}
|
|
16105
16158
|
});
|
|
16106
|
-
return jsx(
|
|
16159
|
+
return jsx(InputCheckboxBasic, {
|
|
16160
|
+
"data-action": actionBoundToUIState.name,
|
|
16107
16161
|
...rest,
|
|
16108
|
-
ref:
|
|
16162
|
+
ref: ref,
|
|
16109
16163
|
loading: loading || actionLoading,
|
|
16110
|
-
|
|
16111
|
-
|
|
16112
|
-
|
|
16113
|
-
|
|
16114
|
-
|
|
16115
|
-
method: "run"
|
|
16116
|
-
});
|
|
16117
|
-
} else {
|
|
16118
|
-
effectiveAction.abort();
|
|
16119
|
-
}
|
|
16120
|
-
onToggle?.(toggleEvent);
|
|
16121
|
-
},
|
|
16122
|
-
children: jsx(ActionRenderer, {
|
|
16123
|
-
action: effectiveAction,
|
|
16124
|
-
children: children
|
|
16125
|
-
})
|
|
16126
|
-
});
|
|
16127
|
-
});
|
|
16128
|
-
|
|
16129
|
-
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
16130
|
-
@layer navi {
|
|
16131
|
-
label {
|
|
16132
|
-
cursor: pointer;
|
|
16133
|
-
}
|
|
16134
|
-
|
|
16135
|
-
label[data-readonly],
|
|
16136
|
-
label[data-disabled] {
|
|
16137
|
-
color: rgba(0, 0, 0, 0.5);
|
|
16138
|
-
cursor: default;
|
|
16164
|
+
onChange: e => {
|
|
16165
|
+
requestAction(e.target, actionBoundToUIState, {
|
|
16166
|
+
event: e
|
|
16167
|
+
});
|
|
16168
|
+
onChange?.(e);
|
|
16139
16169
|
}
|
|
16140
|
-
}
|
|
16141
|
-
`;
|
|
16142
|
-
const ReportReadOnlyOnLabelContext = createContext();
|
|
16143
|
-
const ReportDisabledOnLabelContext = createContext();
|
|
16144
|
-
const Label = props => {
|
|
16145
|
-
const {
|
|
16146
|
-
readOnly,
|
|
16147
|
-
disabled,
|
|
16148
|
-
children,
|
|
16149
|
-
...rest
|
|
16150
|
-
} = props;
|
|
16151
|
-
const [inputReadOnly, setInputReadOnly] = useState(false);
|
|
16152
|
-
const innerReadOnly = readOnly || inputReadOnly;
|
|
16153
|
-
const [inputDisabled, setInputDisabled] = useState(false);
|
|
16154
|
-
const innerDisabled = disabled || inputDisabled;
|
|
16155
|
-
return jsx(Box, {
|
|
16156
|
-
...rest,
|
|
16157
|
-
as: "label",
|
|
16158
|
-
basePseudoState: {
|
|
16159
|
-
readOnly: innerReadOnly,
|
|
16160
|
-
disabled: innerDisabled
|
|
16161
|
-
},
|
|
16162
|
-
children: jsx(ReportReadOnlyOnLabelContext.Provider, {
|
|
16163
|
-
value: setInputReadOnly,
|
|
16164
|
-
children: jsx(ReportDisabledOnLabelContext.Provider, {
|
|
16165
|
-
value: setInputDisabled,
|
|
16166
|
-
children: children
|
|
16167
|
-
})
|
|
16168
|
-
})
|
|
16169
16170
|
});
|
|
16170
16171
|
};
|
|
16172
|
+
const InputCheckboxInsideForm = InputCheckboxBasic;
|
|
16171
16173
|
|
|
16172
16174
|
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
16173
16175
|
@layer navi {
|
|
16174
|
-
.
|
|
16176
|
+
.navi_radio {
|
|
16175
16177
|
--outline-offset: 1px;
|
|
16176
16178
|
--outline-width: 2px;
|
|
16177
|
-
--border-width: 1px;
|
|
16178
|
-
--border-radius: 2px;
|
|
16179
16179
|
--width: 13px;
|
|
16180
16180
|
--height: 13px;
|
|
16181
16181
|
|
|
@@ -16184,12 +16184,11 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
16184
16184
|
--border-color: light-dark(#767676, #8e8e93);
|
|
16185
16185
|
--background-color: white;
|
|
16186
16186
|
--color: light-dark(#4476ff, #3b82f6);
|
|
16187
|
-
--
|
|
16188
|
-
--
|
|
16189
|
-
--checkmark-color: var(--checkmark-color-light);
|
|
16187
|
+
--radiomark-color: var(--color);
|
|
16188
|
+
--border-color-checked: var(--color);
|
|
16190
16189
|
|
|
16191
|
-
--color-mix-light:
|
|
16192
|
-
--color-mix-dark:
|
|
16190
|
+
--color-mix-light: white;
|
|
16191
|
+
--color-mix-dark: black;
|
|
16193
16192
|
--color-mix: var(--color-mix-light);
|
|
16194
16193
|
|
|
16195
16194
|
/* Hover */
|
|
@@ -16199,7 +16198,7 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
16199
16198
|
var(--color) 80%,
|
|
16200
16199
|
var(--color-mix)
|
|
16201
16200
|
);
|
|
16202
|
-
--
|
|
16201
|
+
--radiomark-color-hover: color-mix(
|
|
16203
16202
|
in srgb,
|
|
16204
16203
|
var(--color) 80%,
|
|
16205
16204
|
var(--color-mix)
|
|
@@ -16210,30 +16209,31 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
16210
16209
|
var(--border-color) 30%,
|
|
16211
16210
|
white
|
|
16212
16211
|
);
|
|
16212
|
+
--background-color-readonly: var(--background-color);
|
|
16213
|
+
--radiomark-color-readonly: grey;
|
|
16213
16214
|
--border-color-readonly-checked: #d3d3d3;
|
|
16214
|
-
--background-color-readonly-checked:
|
|
16215
|
-
--checkmark-color-readonly: #eeeeee;
|
|
16215
|
+
--background-color-readonly-checked: #d3d3d3;
|
|
16216
16216
|
/* Disabled */
|
|
16217
16217
|
--border-color-disabled: var(--border-color-readonly);
|
|
16218
16218
|
--background-color-disabled: rgba(248, 248, 248, 0.7);
|
|
16219
|
-
--
|
|
16220
|
-
--border-color-disabled
|
|
16221
|
-
--background-color-disabled-checked:
|
|
16219
|
+
--radiomark-color-disabled: #d3d3d3;
|
|
16220
|
+
--border-color-checked-disabled: #d3d3d3;
|
|
16221
|
+
--background-color-disabled-checked: var(--background-color);
|
|
16222
16222
|
}
|
|
16223
16223
|
|
|
16224
|
-
.
|
|
16224
|
+
.navi_radio[data-dark] {
|
|
16225
16225
|
--color-mix: var(--color-mix-dark);
|
|
16226
|
-
--checkmark-color: var(--navi-checkmark-color-dark);
|
|
16227
16226
|
}
|
|
16228
16227
|
}
|
|
16229
16228
|
|
|
16230
|
-
.
|
|
16229
|
+
.navi_radio {
|
|
16231
16230
|
position: relative;
|
|
16232
16231
|
display: inline-flex;
|
|
16233
16232
|
box-sizing: content-box;
|
|
16234
|
-
margin: 3px
|
|
16233
|
+
margin-top: 3px;
|
|
16234
|
+
margin-right: 3px;
|
|
16235
|
+
margin-left: 5px;
|
|
16235
16236
|
|
|
16236
|
-
--x-border-radius: var(--border-radius);
|
|
16237
16237
|
--x-outline-offset: var(--outline-offset);
|
|
16238
16238
|
--x-outline-width: var(--outline-width);
|
|
16239
16239
|
--x-border-width: var(--border-width);
|
|
@@ -16243,111 +16243,128 @@ installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
|
16243
16243
|
--x-background-color: var(--background-color);
|
|
16244
16244
|
--x-border-color: var(--border-color);
|
|
16245
16245
|
--x-color: var(--color);
|
|
16246
|
-
--x-
|
|
16246
|
+
--x-radiomark-color: var(--radiomark-color);
|
|
16247
16247
|
}
|
|
16248
|
-
.
|
|
16248
|
+
.navi_radio .navi_native_field {
|
|
16249
16249
|
position: absolute;
|
|
16250
16250
|
inset: 0;
|
|
16251
16251
|
margin: 0;
|
|
16252
16252
|
padding: 0;
|
|
16253
|
-
border: none;
|
|
16254
16253
|
opacity: 0;
|
|
16255
16254
|
cursor: inherit;
|
|
16256
16255
|
}
|
|
16257
|
-
.
|
|
16256
|
+
.navi_radio .navi_radio_field {
|
|
16258
16257
|
display: inline-flex;
|
|
16259
16258
|
box-sizing: border-box;
|
|
16260
16259
|
width: var(--x-width);
|
|
16261
16260
|
height: var(--x-height);
|
|
16262
|
-
|
|
16263
|
-
|
|
16264
|
-
border-
|
|
16265
|
-
border-color: var(--x-border-color);
|
|
16266
|
-
border-radius: var(--x-border-radius);
|
|
16261
|
+
align-items: center;
|
|
16262
|
+
justify-content: center;
|
|
16263
|
+
border-radius: 50%;
|
|
16267
16264
|
outline-width: var(--x-outline-width);
|
|
16268
16265
|
outline-style: none;
|
|
16269
16266
|
outline-color: var(--x-outline-color);
|
|
16270
16267
|
outline-offset: var(--x-outline-offset);
|
|
16271
16268
|
}
|
|
16272
|
-
.
|
|
16269
|
+
.navi_radio_field svg {
|
|
16270
|
+
overflow: visible;
|
|
16271
|
+
}
|
|
16272
|
+
.navi_radio_border {
|
|
16273
|
+
fill: var(--x-background-color);
|
|
16274
|
+
stroke: var(--x-border-color);
|
|
16275
|
+
}
|
|
16276
|
+
.navi_radio_marker {
|
|
16273
16277
|
width: 100%;
|
|
16274
16278
|
height: 100%;
|
|
16275
16279
|
opacity: 0;
|
|
16276
|
-
|
|
16277
|
-
transform: scale(0.
|
|
16278
|
-
|
|
16280
|
+
fill: var(--x-radiomark-color);
|
|
16281
|
+
transform: scale(0.3);
|
|
16282
|
+
transform-origin: center;
|
|
16279
16283
|
pointer-events: none;
|
|
16280
16284
|
}
|
|
16281
|
-
.
|
|
16282
|
-
|
|
16283
|
-
|
|
16284
|
-
|
|
16285
|
-
|
|
16286
|
-
|
|
16287
|
-
.
|
|
16288
|
-
|
|
16285
|
+
.navi_radio_dashed_border {
|
|
16286
|
+
display: none;
|
|
16287
|
+
}
|
|
16288
|
+
.navi_radio[data-transition] .navi_radio_marker {
|
|
16289
|
+
transition: all 0.15s ease;
|
|
16290
|
+
}
|
|
16291
|
+
.navi_radio[data-transition] .navi_radio_dashed_border {
|
|
16292
|
+
transition: all 0.15s ease;
|
|
16293
|
+
}
|
|
16294
|
+
.navi_radio[data-transition] .navi_radio_border {
|
|
16295
|
+
transition: all 0.15s ease;
|
|
16296
|
+
}
|
|
16297
|
+
|
|
16298
|
+
/* Focus */
|
|
16299
|
+
.navi_radio[data-focus-visible] .navi_radio_field {
|
|
16300
|
+
outline-style: solid;
|
|
16289
16301
|
}
|
|
16290
16302
|
/* Hover */
|
|
16291
|
-
.
|
|
16303
|
+
.navi_radio[data-hover] {
|
|
16292
16304
|
--x-border-color: var(--border-color-hover);
|
|
16293
|
-
|
|
16294
|
-
.navi_checkbox[data-checked][data-hover] {
|
|
16295
|
-
--x-border-color: var(--border-color-hover-checked);
|
|
16296
|
-
--x-background-color: var(--background-color-hover-checked);
|
|
16305
|
+
--x-radiomark-color: var(--radiomark-color-hover);
|
|
16297
16306
|
}
|
|
16298
16307
|
/* Checked */
|
|
16299
|
-
.
|
|
16300
|
-
--x-
|
|
16301
|
-
|
|
16308
|
+
.navi_radio[data-checked] {
|
|
16309
|
+
--x-border-color: var(--border-color-checked);
|
|
16310
|
+
}
|
|
16311
|
+
.navi_radio[data-checked] .navi_radio_marker {
|
|
16312
|
+
opacity: 1;
|
|
16313
|
+
transform: scale(1);
|
|
16314
|
+
}
|
|
16315
|
+
.navi_radio[data-hover][data-checked] {
|
|
16316
|
+
--x-border-color: var(--border-color-hover-checked);
|
|
16302
16317
|
}
|
|
16303
16318
|
/* Readonly */
|
|
16304
|
-
.
|
|
16305
|
-
.navi_checkbox[data-readonly][data-hover] {
|
|
16306
|
-
--x-border-color: var(--border-color-readonly);
|
|
16319
|
+
.navi_radio[data-readonly] {
|
|
16307
16320
|
--x-background-color: var(--background-color-readonly);
|
|
16321
|
+
--x-border-color: var(--border-color-readonly);
|
|
16322
|
+
--x-radiomark-color: var(--radiomark-color-readonly);
|
|
16308
16323
|
}
|
|
16309
|
-
.
|
|
16310
|
-
|
|
16324
|
+
.navi_radio[data-readonly] .navi_radio_dashed_border {
|
|
16325
|
+
display: none;
|
|
16326
|
+
}
|
|
16327
|
+
.navi_radio[data-readonly][data-checked] {
|
|
16311
16328
|
--x-background-color: var(--background-color-readonly-checked);
|
|
16312
|
-
--x-
|
|
16329
|
+
--x-border-color: var(--border-color-readonly-checked);
|
|
16330
|
+
--x-radiomark-color: var(--radiomark-color-readonly);
|
|
16313
16331
|
}
|
|
16314
16332
|
/* Disabled */
|
|
16315
|
-
.
|
|
16316
|
-
--x-border-color: var(--border-color-disabled);
|
|
16333
|
+
.navi_radio[data-disabled] {
|
|
16317
16334
|
--x-background-color: var(--background-color-disabled);
|
|
16335
|
+
--x-border-color: var(--border-color-disabled);
|
|
16336
|
+
--x-radiomark-color: var(--radiomark-color-disabled);
|
|
16318
16337
|
}
|
|
16319
|
-
.
|
|
16320
|
-
--x-border-color: var(--border-color-disabled
|
|
16321
|
-
--x-
|
|
16322
|
-
--x-checkmark-color: var(--checkmark-color-disabled);
|
|
16338
|
+
.navi_radio[data-disabled][data-checked] {
|
|
16339
|
+
--x-border-color: var(--border-color-disabled);
|
|
16340
|
+
--x-radiomark-color: var(--radiomark-color-disabled);
|
|
16323
16341
|
}
|
|
16324
16342
|
`;
|
|
16325
|
-
const
|
|
16343
|
+
const InputRadio = props => {
|
|
16326
16344
|
const {
|
|
16327
16345
|
value = "on"
|
|
16328
16346
|
} = props;
|
|
16329
|
-
const uiStateController = useUIStateController(props, "
|
|
16347
|
+
const uiStateController = useUIStateController(props, "radio", {
|
|
16330
16348
|
statePropName: "checked",
|
|
16331
|
-
defaultStatePropName: "defaultChecked",
|
|
16332
16349
|
fallbackState: false,
|
|
16333
16350
|
getStateFromProp: checked => checked ? value : undefined,
|
|
16334
16351
|
getPropFromState: Boolean
|
|
16335
16352
|
});
|
|
16336
16353
|
const uiState = useUIState(uiStateController);
|
|
16337
|
-
const
|
|
16338
|
-
Basic:
|
|
16339
|
-
WithAction:
|
|
16340
|
-
InsideForm:
|
|
16354
|
+
const radio = renderActionableComponent(props, {
|
|
16355
|
+
Basic: InputRadioBasic,
|
|
16356
|
+
WithAction: InputRadioWithAction,
|
|
16357
|
+
InsideForm: InputRadioInsideForm
|
|
16341
16358
|
});
|
|
16342
16359
|
return jsx(UIStateControllerContext.Provider, {
|
|
16343
16360
|
value: uiStateController,
|
|
16344
16361
|
children: jsx(UIStateContext.Provider, {
|
|
16345
16362
|
value: uiState,
|
|
16346
|
-
children:
|
|
16363
|
+
children: radio
|
|
16347
16364
|
})
|
|
16348
16365
|
});
|
|
16349
16366
|
};
|
|
16350
|
-
const
|
|
16367
|
+
const RadioStyleCSSVars = {
|
|
16351
16368
|
"outlineWidth": "--outline-width",
|
|
16352
16369
|
"borderWidth": "--border-width",
|
|
16353
16370
|
"borderRadius": "--border-radius",
|
|
@@ -16373,15 +16390,15 @@ const CheckboxStyleCSSVars = {
|
|
|
16373
16390
|
color: "--color-disabled"
|
|
16374
16391
|
}
|
|
16375
16392
|
};
|
|
16376
|
-
const
|
|
16377
|
-
const
|
|
16378
|
-
const
|
|
16379
|
-
const
|
|
16393
|
+
const RadioPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":checked", ":-navi-loading"];
|
|
16394
|
+
const RadioPseudoElements = ["::-navi-loader", "::-navi-radiomark"];
|
|
16395
|
+
const InputRadioBasic = props => {
|
|
16396
|
+
const contextName = useContext(FieldNameContext);
|
|
16380
16397
|
const contextReadOnly = useContext(ReadOnlyContext);
|
|
16381
16398
|
const contextDisabled = useContext(DisabledContext);
|
|
16382
16399
|
const contextRequired = useContext(RequiredContext);
|
|
16383
16400
|
const contextLoading = useContext(LoadingContext);
|
|
16384
|
-
const
|
|
16401
|
+
const contextLoadingElement = useContext(LoadingElementContext);
|
|
16385
16402
|
const uiStateController = useContext(UIStateControllerContext);
|
|
16386
16403
|
const uiState = useContext(UIStateContext);
|
|
16387
16404
|
const reportReadOnlyOnLabel = useContext(ReportReadOnlyOnLabelContext);
|
|
@@ -16389,7 +16406,6 @@ const InputCheckboxBasic = props => {
|
|
|
16389
16406
|
const {
|
|
16390
16407
|
/* eslint-disable no-unused-vars */
|
|
16391
16408
|
type,
|
|
16392
|
-
defaultChecked,
|
|
16393
16409
|
/* eslint-enable no-unused-vars */
|
|
16394
16410
|
|
|
16395
16411
|
name,
|
|
@@ -16406,35 +16422,64 @@ const InputCheckboxBasic = props => {
|
|
|
16406
16422
|
} = props;
|
|
16407
16423
|
const defaultRef = useRef();
|
|
16408
16424
|
const ref = props.ref || defaultRef;
|
|
16409
|
-
const innerName = name ||
|
|
16425
|
+
const innerName = name || contextName;
|
|
16410
16426
|
const innerDisabled = disabled || contextDisabled;
|
|
16411
16427
|
const innerRequired = required || contextRequired;
|
|
16412
|
-
const innerLoading = loading || contextLoading &&
|
|
16428
|
+
const innerLoading = loading || contextLoading && contextLoadingElement === ref.current;
|
|
16413
16429
|
const innerReadOnly = readOnly || contextReadOnly || innerLoading || uiStateController.readOnly;
|
|
16414
16430
|
reportReadOnlyOnLabel?.(innerReadOnly);
|
|
16415
16431
|
reportDisabledOnLabel?.(innerDisabled);
|
|
16416
16432
|
useAutoFocus(ref, autoFocus);
|
|
16417
16433
|
useConstraints(ref, constraints);
|
|
16418
16434
|
const checked = Boolean(uiState);
|
|
16435
|
+
// we must first dispatch an event to inform all other radios they where unchecked
|
|
16436
|
+
// this way each other radio uiStateController knows thery are unchecked
|
|
16437
|
+
// we do this on "input"
|
|
16438
|
+
// but also when we are becoming checked from outside (hence the useLayoutEffect)
|
|
16439
|
+
const updateOtherRadiosInGroup = () => {
|
|
16440
|
+
const thisRadio = ref.current;
|
|
16441
|
+
const radioList = thisRadio.closest("[data-radio-list]");
|
|
16442
|
+
if (!radioList) {
|
|
16443
|
+
return;
|
|
16444
|
+
}
|
|
16445
|
+
const radioInputs = radioList.querySelectorAll(`input[type="radio"][name="${thisRadio.name}"]`);
|
|
16446
|
+
for (const radioInput of radioInputs) {
|
|
16447
|
+
if (radioInput === thisRadio) {
|
|
16448
|
+
continue;
|
|
16449
|
+
}
|
|
16450
|
+
radioInput.dispatchEvent(new CustomEvent("setuistate", {
|
|
16451
|
+
detail: false
|
|
16452
|
+
}));
|
|
16453
|
+
}
|
|
16454
|
+
};
|
|
16455
|
+
useLayoutEffect(() => {
|
|
16456
|
+
if (checked) {
|
|
16457
|
+
updateOtherRadiosInGroup();
|
|
16458
|
+
}
|
|
16459
|
+
}, [checked]);
|
|
16460
|
+
const innerOnInput = useStableCallback(e => {
|
|
16461
|
+
const radio = e.target;
|
|
16462
|
+
const radioIsChecked = radio.checked;
|
|
16463
|
+
if (radioIsChecked) {
|
|
16464
|
+
updateOtherRadiosInGroup();
|
|
16465
|
+
}
|
|
16466
|
+
uiStateController.setUIState(radioIsChecked, e);
|
|
16467
|
+
onInput?.(e);
|
|
16468
|
+
});
|
|
16419
16469
|
const innerOnClick = useStableCallback(e => {
|
|
16420
16470
|
if (innerReadOnly) {
|
|
16421
16471
|
e.preventDefault();
|
|
16422
16472
|
}
|
|
16423
16473
|
onClick?.(e);
|
|
16424
16474
|
});
|
|
16425
|
-
const
|
|
16426
|
-
|
|
16427
|
-
const checkboxIsChecked = checkbox.checked;
|
|
16428
|
-
uiStateController.setUIState(checkboxIsChecked, e);
|
|
16429
|
-
onInput?.(e);
|
|
16430
|
-
});
|
|
16431
|
-
const renderCheckbox = checkboxProps => jsx(Box, {
|
|
16432
|
-
...checkboxProps,
|
|
16475
|
+
const renderRadio = radioProps => jsx(Box, {
|
|
16476
|
+
...radioProps,
|
|
16433
16477
|
as: "input",
|
|
16434
16478
|
ref: ref,
|
|
16435
|
-
type: "
|
|
16479
|
+
type: "radio",
|
|
16436
16480
|
name: innerName,
|
|
16437
16481
|
checked: checked,
|
|
16482
|
+
disabled: innerDisabled,
|
|
16438
16483
|
required: innerRequired,
|
|
16439
16484
|
baseClassName: "navi_native_field",
|
|
16440
16485
|
"data-callout-arrow-x": "center",
|
|
@@ -16447,27 +16492,25 @@ const InputCheckboxBasic = props => {
|
|
|
16447
16492
|
uiStateController.setUIState(e.detail.value, e);
|
|
16448
16493
|
}
|
|
16449
16494
|
});
|
|
16450
|
-
const
|
|
16495
|
+
const renderRadioMemoized = useCallback(renderRadio, [innerName, checked, innerRequired]);
|
|
16451
16496
|
useLayoutEffect(() => {
|
|
16452
|
-
const
|
|
16453
|
-
const
|
|
16454
|
-
|
|
16455
|
-
|
|
16456
|
-
if (colorPicked === lightColor) {
|
|
16457
|
-
naviCheckbox.removeAttribute("data-dark");
|
|
16497
|
+
const naviRadio = ref.current;
|
|
16498
|
+
const luminance = resolveColorLuminance("var(--color)", naviRadio);
|
|
16499
|
+
if (luminance < 0.3) {
|
|
16500
|
+
naviRadio.setAttribute("data-dark", "");
|
|
16458
16501
|
} else {
|
|
16459
|
-
|
|
16502
|
+
naviRadio.removeAttribute("data-dark");
|
|
16460
16503
|
}
|
|
16461
16504
|
}, [color]);
|
|
16462
16505
|
return jsxs(Box, {
|
|
16463
16506
|
as: "span",
|
|
16464
16507
|
...rest,
|
|
16465
16508
|
ref: ref,
|
|
16466
|
-
baseClassName: "
|
|
16509
|
+
baseClassName: "navi_radio",
|
|
16467
16510
|
pseudoStateSelector: ".navi_native_field",
|
|
16468
|
-
styleCSSVars:
|
|
16469
|
-
pseudoClasses:
|
|
16470
|
-
pseudoElements:
|
|
16511
|
+
styleCSSVars: RadioStyleCSSVars,
|
|
16512
|
+
pseudoClasses: RadioPseudoClasses,
|
|
16513
|
+
pseudoElements: RadioPseudoElements,
|
|
16471
16514
|
basePseudoState: {
|
|
16472
16515
|
":read-only": innerReadOnly,
|
|
16473
16516
|
":disabled": innerDisabled,
|
|
@@ -16478,286 +16521,186 @@ const InputCheckboxBasic = props => {
|
|
|
16478
16521
|
children: [jsx(LoaderBackground, {
|
|
16479
16522
|
loading: innerLoading,
|
|
16480
16523
|
inset: -1,
|
|
16524
|
+
targetSelector: ".navi_radio_field",
|
|
16481
16525
|
color: "var(--loader-color)"
|
|
16482
|
-
}),
|
|
16483
|
-
className: "
|
|
16484
|
-
children:
|
|
16526
|
+
}), renderRadioMemoized, jsx("span", {
|
|
16527
|
+
className: "navi_radio_field",
|
|
16528
|
+
children: jsxs("svg", {
|
|
16485
16529
|
viewBox: "0 0 12 12",
|
|
16486
16530
|
"aria-hidden": "true",
|
|
16487
|
-
|
|
16488
|
-
children: jsx("
|
|
16489
|
-
|
|
16490
|
-
|
|
16491
|
-
|
|
16492
|
-
|
|
16531
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
16532
|
+
children: [jsx("circle", {
|
|
16533
|
+
className: "navi_radio_border",
|
|
16534
|
+
cx: "6",
|
|
16535
|
+
cy: "6",
|
|
16536
|
+
r: "5.5",
|
|
16537
|
+
strokeWidth: "1"
|
|
16538
|
+
}), jsx("circle", {
|
|
16539
|
+
className: "navi_radio_dashed_border",
|
|
16540
|
+
cx: "6",
|
|
16541
|
+
cy: "6",
|
|
16542
|
+
r: "5.5",
|
|
16543
|
+
strokeWidth: "1",
|
|
16544
|
+
strokeDasharray: "2.16 2.16",
|
|
16545
|
+
strokeDashoffset: "0"
|
|
16546
|
+
}), jsx("circle", {
|
|
16547
|
+
className: "navi_radio_marker",
|
|
16548
|
+
cx: "6",
|
|
16549
|
+
cy: "6",
|
|
16550
|
+
r: "3.5"
|
|
16551
|
+
})]
|
|
16493
16552
|
})
|
|
16494
16553
|
})]
|
|
16495
16554
|
});
|
|
16496
16555
|
};
|
|
16497
|
-
const
|
|
16498
|
-
|
|
16499
|
-
|
|
16500
|
-
|
|
16501
|
-
action,
|
|
16502
|
-
onCancel,
|
|
16503
|
-
onChange,
|
|
16504
|
-
actionErrorEffect,
|
|
16505
|
-
onActionPrevented,
|
|
16506
|
-
onActionStart,
|
|
16507
|
-
onActionAbort,
|
|
16508
|
-
onActionError,
|
|
16509
|
-
onActionEnd,
|
|
16510
|
-
loading,
|
|
16511
|
-
...rest
|
|
16512
|
-
} = props;
|
|
16513
|
-
const defaultRef = useRef();
|
|
16514
|
-
const ref = props.ref || defaultRef;
|
|
16515
|
-
const [actionBoundToUIState] = useActionBoundToOneParam(action, uiState);
|
|
16516
|
-
const {
|
|
16517
|
-
loading: actionLoading
|
|
16518
|
-
} = useActionStatus(actionBoundToUIState);
|
|
16519
|
-
const executeAction = useExecuteAction(ref, {
|
|
16520
|
-
errorEffect: actionErrorEffect
|
|
16521
|
-
});
|
|
16522
|
-
|
|
16523
|
-
// In this situation updating the ui state === calling associated action
|
|
16524
|
-
// so cance/abort/error have to revert the ui state to the one before user interaction
|
|
16525
|
-
// to show back the real state of the checkbox (not the one user tried to set)
|
|
16526
|
-
useActionEvents(ref, {
|
|
16527
|
-
onCancel: (e, reason) => {
|
|
16528
|
-
if (reason === "blur_invalid") {
|
|
16529
|
-
return;
|
|
16530
|
-
}
|
|
16531
|
-
uiStateController.resetUIState(e);
|
|
16532
|
-
onCancel?.(e, reason);
|
|
16533
|
-
},
|
|
16534
|
-
onPrevented: onActionPrevented,
|
|
16535
|
-
onAction: executeAction,
|
|
16536
|
-
onStart: onActionStart,
|
|
16537
|
-
onAbort: e => {
|
|
16538
|
-
uiStateController.resetUIState(e);
|
|
16539
|
-
onActionAbort?.(e);
|
|
16540
|
-
},
|
|
16541
|
-
onError: e => {
|
|
16542
|
-
uiStateController.resetUIState(e);
|
|
16543
|
-
onActionError?.(e);
|
|
16544
|
-
},
|
|
16545
|
-
onEnd: e => {
|
|
16546
|
-
onActionEnd?.(e);
|
|
16547
|
-
}
|
|
16548
|
-
});
|
|
16549
|
-
return jsx(InputCheckboxBasic, {
|
|
16550
|
-
"data-action": actionBoundToUIState.name,
|
|
16551
|
-
...rest,
|
|
16552
|
-
ref: ref,
|
|
16553
|
-
loading: loading || actionLoading,
|
|
16554
|
-
onChange: e => {
|
|
16555
|
-
requestAction(e.target, actionBoundToUIState, {
|
|
16556
|
-
event: e
|
|
16557
|
-
});
|
|
16558
|
-
onChange?.(e);
|
|
16559
|
-
}
|
|
16560
|
-
});
|
|
16561
|
-
};
|
|
16562
|
-
const InputCheckboxInsideForm = InputCheckboxBasic;
|
|
16556
|
+
const InputRadioWithAction = () => {
|
|
16557
|
+
throw new Error(`<Input type="radio" /> with an action make no sense. Use <RadioList action={something} /> instead`);
|
|
16558
|
+
};
|
|
16559
|
+
const InputRadioInsideForm = InputRadio;
|
|
16563
16560
|
|
|
16564
16561
|
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
16565
16562
|
@layer navi {
|
|
16566
|
-
.
|
|
16567
|
-
--
|
|
16568
|
-
--
|
|
16569
|
-
--width:
|
|
16570
|
-
--
|
|
16563
|
+
.navi_input {
|
|
16564
|
+
--border-radius: 2px;
|
|
16565
|
+
--border-width: 1px;
|
|
16566
|
+
--outline-width: 1px;
|
|
16567
|
+
--outer-width: calc(var(--border-width) + var(--outline-width));
|
|
16571
16568
|
|
|
16569
|
+
/* Default */
|
|
16572
16570
|
--outline-color: var(--navi-focus-outline-color);
|
|
16573
16571
|
--loader-color: var(--navi-loader-color);
|
|
16574
16572
|
--border-color: light-dark(#767676, #8e8e93);
|
|
16575
16573
|
--background-color: white;
|
|
16576
|
-
--color:
|
|
16577
|
-
--
|
|
16578
|
-
--
|
|
16579
|
-
|
|
16580
|
-
--color-mix-light: white;
|
|
16581
|
-
--color-mix-dark: black;
|
|
16582
|
-
--color-mix: var(--color-mix-light);
|
|
16583
|
-
|
|
16574
|
+
--color: currentColor;
|
|
16575
|
+
--color-dimmed: color-mix(in srgb, currentColor 60%, transparent);
|
|
16576
|
+
--placeholder-color: var(--color-dimmed);
|
|
16584
16577
|
/* Hover */
|
|
16585
|
-
--border-color-hover: color-mix(in srgb, var(--border-color)
|
|
16586
|
-
--
|
|
16587
|
-
in srgb,
|
|
16588
|
-
var(--color) 80%,
|
|
16589
|
-
var(--color-mix)
|
|
16590
|
-
);
|
|
16591
|
-
--radiomark-color-hover: color-mix(
|
|
16578
|
+
--border-color-hover: color-mix(in srgb, var(--border-color) 70%, black);
|
|
16579
|
+
--background-color-hover: color-mix(
|
|
16592
16580
|
in srgb,
|
|
16593
|
-
var(--color)
|
|
16594
|
-
|
|
16581
|
+
var(--background-color) 95%,
|
|
16582
|
+
black
|
|
16595
16583
|
);
|
|
16584
|
+
--color-hover: var(--color);
|
|
16585
|
+
/* Active */
|
|
16586
|
+
--border-color-active: color-mix(in srgb, var(--border-color) 90%, black);
|
|
16596
16587
|
/* Readonly */
|
|
16597
16588
|
--border-color-readonly: color-mix(
|
|
16598
16589
|
in srgb,
|
|
16599
|
-
var(--border-color)
|
|
16600
|
-
|
|
16590
|
+
var(--border-color) 45%,
|
|
16591
|
+
transparent
|
|
16601
16592
|
);
|
|
16602
16593
|
--background-color-readonly: var(--background-color);
|
|
16603
|
-
--
|
|
16604
|
-
--border-color-readonly-checked: #d3d3d3;
|
|
16605
|
-
--background-color-readonly-checked: #d3d3d3;
|
|
16594
|
+
--color-readonly: var(--color-dimmed);
|
|
16606
16595
|
/* Disabled */
|
|
16607
16596
|
--border-color-disabled: var(--border-color-readonly);
|
|
16608
|
-
--background-color-disabled:
|
|
16609
|
-
|
|
16610
|
-
|
|
16611
|
-
|
|
16612
|
-
|
|
16613
|
-
|
|
16614
|
-
.navi_radio[data-dark] {
|
|
16615
|
-
--color-mix: var(--color-mix-dark);
|
|
16597
|
+
--background-color-disabled: color-mix(
|
|
16598
|
+
in srgb,
|
|
16599
|
+
var(--background-color) 95%,
|
|
16600
|
+
grey
|
|
16601
|
+
);
|
|
16602
|
+
--color-disabled: color-mix(in srgb, var(--color) 95%, grey);
|
|
16616
16603
|
}
|
|
16617
16604
|
}
|
|
16618
16605
|
|
|
16619
|
-
.
|
|
16606
|
+
.navi_input {
|
|
16620
16607
|
position: relative;
|
|
16621
|
-
|
|
16622
|
-
|
|
16623
|
-
|
|
16624
|
-
|
|
16625
|
-
|
|
16608
|
+
box-sizing: border-box;
|
|
16609
|
+
width: fit-content;
|
|
16610
|
+
height: fit-content;
|
|
16611
|
+
flex-direction: inherit;
|
|
16612
|
+
border-radius: inherit;
|
|
16613
|
+
cursor: inherit;
|
|
16626
16614
|
|
|
16627
|
-
--x-outline-offset: var(--outline-offset);
|
|
16628
16615
|
--x-outline-width: var(--outline-width);
|
|
16616
|
+
--x-border-radius: var(--border-radius);
|
|
16629
16617
|
--x-border-width: var(--border-width);
|
|
16630
|
-
--x-width: var(--width);
|
|
16631
|
-
--x-height: var(--height);
|
|
16618
|
+
--x-outer-width: calc(var(--x-border-width) + var(--x-outline-width));
|
|
16632
16619
|
--x-outline-color: var(--outline-color);
|
|
16633
|
-
--x-background-color: var(--background-color);
|
|
16634
16620
|
--x-border-color: var(--border-color);
|
|
16621
|
+
--x-background-color: var(--background-color);
|
|
16635
16622
|
--x-color: var(--color);
|
|
16636
|
-
--x-
|
|
16637
|
-
}
|
|
16638
|
-
.navi_radio .navi_native_field {
|
|
16639
|
-
position: absolute;
|
|
16640
|
-
inset: 0;
|
|
16641
|
-
margin: 0;
|
|
16642
|
-
padding: 0;
|
|
16643
|
-
opacity: 0;
|
|
16644
|
-
cursor: inherit;
|
|
16645
|
-
}
|
|
16646
|
-
.navi_radio .navi_radio_field {
|
|
16647
|
-
display: inline-flex;
|
|
16648
|
-
box-sizing: border-box;
|
|
16649
|
-
width: var(--x-width);
|
|
16650
|
-
height: var(--x-height);
|
|
16651
|
-
align-items: center;
|
|
16652
|
-
justify-content: center;
|
|
16653
|
-
border-radius: 50%;
|
|
16654
|
-
outline-width: var(--x-outline-width);
|
|
16655
|
-
outline-style: none;
|
|
16656
|
-
outline-color: var(--x-outline-color);
|
|
16657
|
-
outline-offset: var(--x-outline-offset);
|
|
16658
|
-
}
|
|
16659
|
-
.navi_radio_field svg {
|
|
16660
|
-
overflow: visible;
|
|
16661
|
-
}
|
|
16662
|
-
.navi_radio_border {
|
|
16663
|
-
fill: var(--x-background-color);
|
|
16664
|
-
stroke: var(--x-border-color);
|
|
16665
|
-
}
|
|
16666
|
-
.navi_radio_marker {
|
|
16667
|
-
width: 100%;
|
|
16668
|
-
height: 100%;
|
|
16669
|
-
opacity: 0;
|
|
16670
|
-
fill: var(--x-radiomark-color);
|
|
16671
|
-
transform: scale(0.3);
|
|
16672
|
-
transform-origin: center;
|
|
16673
|
-
pointer-events: none;
|
|
16674
|
-
}
|
|
16675
|
-
.navi_radio_dashed_border {
|
|
16676
|
-
display: none;
|
|
16677
|
-
}
|
|
16678
|
-
.navi_radio[data-transition] .navi_radio_marker {
|
|
16679
|
-
transition: all 0.15s ease;
|
|
16680
|
-
}
|
|
16681
|
-
.navi_radio[data-transition] .navi_radio_dashed_border {
|
|
16682
|
-
transition: all 0.15s ease;
|
|
16683
|
-
}
|
|
16684
|
-
.navi_radio[data-transition] .navi_radio_border {
|
|
16685
|
-
transition: all 0.15s ease;
|
|
16623
|
+
--x-placeholder-color: var(--placeholder-color);
|
|
16686
16624
|
}
|
|
16687
16625
|
|
|
16688
|
-
|
|
16689
|
-
|
|
16626
|
+
.navi_input .navi_native_input {
|
|
16627
|
+
box-sizing: border-box;
|
|
16628
|
+
padding-top: var(--padding-top, var(--padding-y, var(--padding, 1px)));
|
|
16629
|
+
padding-right: var(--padding-right, var(--padding-x, var(--padding, 2px)));
|
|
16630
|
+
padding-bottom: var(
|
|
16631
|
+
--padding-bottom,
|
|
16632
|
+
var(--padding-y, var(--padding, 1px))
|
|
16633
|
+
);
|
|
16634
|
+
padding-left: var(--padding-left, var(--padding-x, var(--padding, 2px)));
|
|
16635
|
+
color: var(--x-color);
|
|
16636
|
+
background-color: var(--x-background-color);
|
|
16637
|
+
border-width: var(--x-outer-width);
|
|
16638
|
+
border-width: var(--x-outer-width);
|
|
16639
|
+
border-style: solid;
|
|
16640
|
+
border-color: transparent;
|
|
16641
|
+
border-radius: var(--x-border-radius);
|
|
16642
|
+
outline-width: var(--x-border-width);
|
|
16690
16643
|
outline-style: solid;
|
|
16644
|
+
outline-color: var(--x-border-color);
|
|
16645
|
+
outline-offset: calc(-1 * (var(--x-border-width)));
|
|
16691
16646
|
}
|
|
16692
|
-
|
|
16693
|
-
|
|
16694
|
-
--x-border-color: var(--border-color-hover);
|
|
16695
|
-
--x-radiomark-color: var(--radiomark-color-hover);
|
|
16696
|
-
}
|
|
16697
|
-
/* Checked */
|
|
16698
|
-
.navi_radio[data-checked] {
|
|
16699
|
-
--x-border-color: var(--border-color-checked);
|
|
16700
|
-
}
|
|
16701
|
-
.navi_radio[data-checked] .navi_radio_marker {
|
|
16702
|
-
opacity: 1;
|
|
16703
|
-
transform: scale(1);
|
|
16647
|
+
.navi_input .navi_native_input::placeholder {
|
|
16648
|
+
color: var(--x-placeholder-color);
|
|
16704
16649
|
}
|
|
16705
|
-
.
|
|
16706
|
-
|
|
16650
|
+
.navi_input .navi_native_input:-internal-autofill-selected {
|
|
16651
|
+
/* Webkit is putting some nasty styles after automplete that look as follow */
|
|
16652
|
+
/* input:-internal-autofill-selected { color: FieldText !important; } */
|
|
16653
|
+
/* Fortunately we can override it as follow */
|
|
16654
|
+
-webkit-text-fill-color: var(--x-color) !important;
|
|
16707
16655
|
}
|
|
16708
16656
|
/* Readonly */
|
|
16709
|
-
.
|
|
16710
|
-
--x-background-color: var(--background-color-readonly);
|
|
16657
|
+
.navi_input[data-readonly] {
|
|
16711
16658
|
--x-border-color: var(--border-color-readonly);
|
|
16712
|
-
--x-
|
|
16713
|
-
|
|
16714
|
-
.navi_radio[data-readonly] .navi_radio_dashed_border {
|
|
16715
|
-
display: none;
|
|
16659
|
+
--x-background-color: var(--background-color-readonly);
|
|
16660
|
+
--x-color: var(--color-readonly);
|
|
16716
16661
|
}
|
|
16717
|
-
|
|
16718
|
-
|
|
16719
|
-
|
|
16720
|
-
|
|
16662
|
+
/* Focus */
|
|
16663
|
+
.navi_input[data-focus] .navi_native_input,
|
|
16664
|
+
.navi_input[data-focus-visible] .navi_native_input {
|
|
16665
|
+
outline-width: var(--x-outer-width);
|
|
16666
|
+
outline-offset: calc(-1 * var(--x-outer-width));
|
|
16667
|
+
--x-border-color: var(--x-outline-color);
|
|
16721
16668
|
}
|
|
16722
16669
|
/* Disabled */
|
|
16723
|
-
.
|
|
16724
|
-
--x-background-color: var(--background-color-disabled);
|
|
16670
|
+
.navi_input[data-disabled] {
|
|
16725
16671
|
--x-border-color: var(--border-color-disabled);
|
|
16726
|
-
--x-
|
|
16672
|
+
--x-background-color: var(--background-color-disabled);
|
|
16673
|
+
--x-color: var(--color-disabled);
|
|
16727
16674
|
}
|
|
16728
|
-
|
|
16729
|
-
|
|
16730
|
-
--x-
|
|
16675
|
+
/* Callout (info, warning, error) */
|
|
16676
|
+
.navi_input[data-callout] {
|
|
16677
|
+
--x-border-color: var(--callout-color);
|
|
16731
16678
|
}
|
|
16732
16679
|
`;
|
|
16733
|
-
const
|
|
16734
|
-
const
|
|
16735
|
-
value = "on"
|
|
16736
|
-
} = props;
|
|
16737
|
-
const uiStateController = useUIStateController(props, "radio", {
|
|
16738
|
-
statePropName: "checked",
|
|
16739
|
-
fallbackState: false,
|
|
16740
|
-
getStateFromProp: checked => checked ? value : undefined,
|
|
16741
|
-
getPropFromState: Boolean
|
|
16742
|
-
});
|
|
16680
|
+
const InputTextual = props => {
|
|
16681
|
+
const uiStateController = useUIStateController(props, "input");
|
|
16743
16682
|
const uiState = useUIState(uiStateController);
|
|
16744
|
-
const
|
|
16745
|
-
Basic:
|
|
16746
|
-
WithAction:
|
|
16747
|
-
InsideForm:
|
|
16683
|
+
const input = renderActionableComponent(props, {
|
|
16684
|
+
Basic: InputTextualBasic,
|
|
16685
|
+
WithAction: InputTextualWithAction,
|
|
16686
|
+
InsideForm: InputTextualInsideForm
|
|
16748
16687
|
});
|
|
16749
16688
|
return jsx(UIStateControllerContext.Provider, {
|
|
16750
16689
|
value: uiStateController,
|
|
16751
16690
|
children: jsx(UIStateContext.Provider, {
|
|
16752
16691
|
value: uiState,
|
|
16753
|
-
children:
|
|
16692
|
+
children: input
|
|
16754
16693
|
})
|
|
16755
16694
|
});
|
|
16756
16695
|
};
|
|
16757
|
-
const
|
|
16696
|
+
const InputStyleCSSVars = {
|
|
16758
16697
|
"outlineWidth": "--outline-width",
|
|
16759
16698
|
"borderWidth": "--border-width",
|
|
16760
16699
|
"borderRadius": "--border-radius",
|
|
16700
|
+
"paddingTop": "--padding-top",
|
|
16701
|
+
"paddingRight": "--padding-right",
|
|
16702
|
+
"paddingBottom": "--padding-bottom",
|
|
16703
|
+
"paddingLeft": "--padding-left",
|
|
16761
16704
|
"backgroundColor": "--background-color",
|
|
16762
16705
|
"borderColor": "--border-color",
|
|
16763
16706
|
"color": "--color",
|
|
@@ -16780,814 +16723,728 @@ const RadioStyleCSSVars = {
|
|
|
16780
16723
|
color: "--color-disabled"
|
|
16781
16724
|
}
|
|
16782
16725
|
};
|
|
16783
|
-
const
|
|
16784
|
-
const
|
|
16785
|
-
const
|
|
16786
|
-
const contextName = useContext(FieldNameContext);
|
|
16726
|
+
const InputPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
|
|
16727
|
+
const InputPseudoElements = ["::-navi-loader"];
|
|
16728
|
+
const InputTextualBasic = props => {
|
|
16787
16729
|
const contextReadOnly = useContext(ReadOnlyContext);
|
|
16788
16730
|
const contextDisabled = useContext(DisabledContext);
|
|
16789
|
-
const contextRequired = useContext(RequiredContext);
|
|
16790
16731
|
const contextLoading = useContext(LoadingContext);
|
|
16791
16732
|
const contextLoadingElement = useContext(LoadingElementContext);
|
|
16733
|
+
const reportReadOnlyOnLabel = useContext(ReportReadOnlyOnLabelContext);
|
|
16792
16734
|
const uiStateController = useContext(UIStateControllerContext);
|
|
16793
16735
|
const uiState = useContext(UIStateContext);
|
|
16794
|
-
const reportReadOnlyOnLabel = useContext(ReportReadOnlyOnLabelContext);
|
|
16795
|
-
const reportDisabledOnLabel = useContext(ReportDisabledOnLabelContext);
|
|
16796
16736
|
const {
|
|
16797
|
-
/* eslint-disable no-unused-vars */
|
|
16798
16737
|
type,
|
|
16799
|
-
|
|
16800
|
-
|
|
16801
|
-
name,
|
|
16738
|
+
onInput,
|
|
16802
16739
|
readOnly,
|
|
16803
16740
|
disabled,
|
|
16804
|
-
|
|
16741
|
+
constraints = [],
|
|
16805
16742
|
loading,
|
|
16806
16743
|
autoFocus,
|
|
16807
|
-
|
|
16808
|
-
|
|
16809
|
-
onInput,
|
|
16810
|
-
color,
|
|
16744
|
+
autoFocusVisible,
|
|
16745
|
+
autoSelect,
|
|
16811
16746
|
...rest
|
|
16812
16747
|
} = props;
|
|
16813
16748
|
const defaultRef = useRef();
|
|
16814
16749
|
const ref = props.ref || defaultRef;
|
|
16815
|
-
const
|
|
16816
|
-
const innerDisabled = disabled || contextDisabled;
|
|
16817
|
-
const innerRequired = required || contextRequired;
|
|
16750
|
+
const innerValue = type === "datetime-local" ? convertToLocalTimezone(uiState) : uiState;
|
|
16818
16751
|
const innerLoading = loading || contextLoading && contextLoadingElement === ref.current;
|
|
16819
16752
|
const innerReadOnly = readOnly || contextReadOnly || innerLoading || uiStateController.readOnly;
|
|
16753
|
+
const innerDisabled = disabled || contextDisabled;
|
|
16754
|
+
// infom any <label> parent of our readOnly state
|
|
16820
16755
|
reportReadOnlyOnLabel?.(innerReadOnly);
|
|
16821
|
-
|
|
16822
|
-
|
|
16756
|
+
useAutoFocus(ref, autoFocus, {
|
|
16757
|
+
autoFocusVisible,
|
|
16758
|
+
autoSelect
|
|
16759
|
+
});
|
|
16823
16760
|
useConstraints(ref, constraints);
|
|
16824
|
-
const
|
|
16825
|
-
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
|
|
16830
|
-
|
|
16831
|
-
|
|
16832
|
-
|
|
16833
|
-
|
|
16834
|
-
|
|
16835
|
-
|
|
16836
|
-
|
|
16837
|
-
|
|
16838
|
-
|
|
16761
|
+
const innerOnInput = useStableCallback(onInput);
|
|
16762
|
+
const renderInput = inputProps => {
|
|
16763
|
+
return jsx(Box, {
|
|
16764
|
+
...inputProps,
|
|
16765
|
+
as: "input",
|
|
16766
|
+
ref: ref,
|
|
16767
|
+
type: type,
|
|
16768
|
+
"data-value": uiState,
|
|
16769
|
+
value: innerValue,
|
|
16770
|
+
onInput: e => {
|
|
16771
|
+
let inputValue;
|
|
16772
|
+
if (type === "number") {
|
|
16773
|
+
inputValue = e.target.valueAsNumber;
|
|
16774
|
+
} else if (type === "datetime-local") {
|
|
16775
|
+
inputValue = convertToUTCTimezone(e.target.value);
|
|
16776
|
+
} else {
|
|
16777
|
+
inputValue = e.target.value;
|
|
16778
|
+
}
|
|
16779
|
+
uiStateController.setUIState(inputValue, e);
|
|
16780
|
+
innerOnInput?.(e);
|
|
16781
|
+
},
|
|
16782
|
+
onresetuistate: e => {
|
|
16783
|
+
uiStateController.resetUIState(e);
|
|
16784
|
+
},
|
|
16785
|
+
onsetuistate: e => {
|
|
16786
|
+
uiStateController.setUIState(e.detail.value, e);
|
|
16839
16787
|
}
|
|
16840
|
-
|
|
16841
|
-
|
|
16842
|
-
|
|
16843
|
-
}
|
|
16788
|
+
// style management
|
|
16789
|
+
,
|
|
16790
|
+
baseClassName: "navi_native_input"
|
|
16791
|
+
});
|
|
16844
16792
|
};
|
|
16845
|
-
|
|
16846
|
-
if (checked) {
|
|
16847
|
-
updateOtherRadiosInGroup();
|
|
16848
|
-
}
|
|
16849
|
-
}, [checked]);
|
|
16850
|
-
const innerOnInput = useStableCallback(e => {
|
|
16851
|
-
const radio = e.target;
|
|
16852
|
-
const radioIsChecked = radio.checked;
|
|
16853
|
-
if (radioIsChecked) {
|
|
16854
|
-
updateOtherRadiosInGroup();
|
|
16855
|
-
}
|
|
16856
|
-
uiStateController.setUIState(radioIsChecked, e);
|
|
16857
|
-
onInput?.(e);
|
|
16858
|
-
});
|
|
16859
|
-
const innerOnClick = useStableCallback(e => {
|
|
16860
|
-
if (innerReadOnly) {
|
|
16861
|
-
e.preventDefault();
|
|
16862
|
-
}
|
|
16863
|
-
onClick?.(e);
|
|
16864
|
-
});
|
|
16865
|
-
const renderRadio = radioProps => jsx(Box, {
|
|
16866
|
-
...radioProps,
|
|
16867
|
-
as: "input",
|
|
16868
|
-
ref: ref,
|
|
16869
|
-
type: "radio",
|
|
16870
|
-
name: innerName,
|
|
16871
|
-
checked: checked,
|
|
16872
|
-
disabled: innerDisabled,
|
|
16873
|
-
required: innerRequired,
|
|
16874
|
-
baseClassName: "navi_native_field",
|
|
16875
|
-
"data-callout-arrow-x": "center",
|
|
16876
|
-
onClick: innerOnClick,
|
|
16877
|
-
onInput: innerOnInput,
|
|
16878
|
-
onresetuistate: e => {
|
|
16879
|
-
uiStateController.resetUIState(e);
|
|
16880
|
-
},
|
|
16881
|
-
onsetuistate: e => {
|
|
16882
|
-
uiStateController.setUIState(e.detail.value, e);
|
|
16883
|
-
}
|
|
16884
|
-
});
|
|
16885
|
-
const renderRadioMemoized = useCallback(renderRadio, [innerName, checked, innerRequired]);
|
|
16886
|
-
useLayoutEffect(() => {
|
|
16887
|
-
const naviRadio = ref.current;
|
|
16888
|
-
const luminance = resolveColorLuminance("var(--color)", naviRadio);
|
|
16889
|
-
if (luminance < 0.3) {
|
|
16890
|
-
naviRadio.setAttribute("data-dark", "");
|
|
16891
|
-
} else {
|
|
16892
|
-
naviRadio.removeAttribute("data-dark");
|
|
16893
|
-
}
|
|
16894
|
-
}, [color]);
|
|
16793
|
+
const renderInputMemoized = useCallback(renderInput, [type, uiState, innerValue, innerOnInput]);
|
|
16895
16794
|
return jsxs(Box, {
|
|
16896
16795
|
as: "span",
|
|
16897
|
-
|
|
16898
|
-
|
|
16899
|
-
|
|
16900
|
-
pseudoStateSelector: ".
|
|
16901
|
-
|
|
16902
|
-
pseudoClasses: RadioPseudoClasses,
|
|
16903
|
-
pseudoElements: RadioPseudoElements,
|
|
16796
|
+
box: true,
|
|
16797
|
+
baseClassName: "navi_input",
|
|
16798
|
+
styleCSSVars: InputStyleCSSVars,
|
|
16799
|
+
pseudoStateSelector: ".navi_native_input",
|
|
16800
|
+
visualSelector: ".navi_native_input",
|
|
16904
16801
|
basePseudoState: {
|
|
16905
16802
|
":read-only": innerReadOnly,
|
|
16906
16803
|
":disabled": innerDisabled,
|
|
16907
16804
|
":-navi-loading": innerLoading
|
|
16908
16805
|
},
|
|
16909
|
-
|
|
16806
|
+
pseudoClasses: InputPseudoClasses,
|
|
16807
|
+
pseudoElements: InputPseudoElements,
|
|
16910
16808
|
hasChildFunction: true,
|
|
16809
|
+
...rest,
|
|
16911
16810
|
children: [jsx(LoaderBackground, {
|
|
16912
16811
|
loading: innerLoading,
|
|
16913
|
-
|
|
16914
|
-
|
|
16915
|
-
|
|
16916
|
-
}), renderRadioMemoized, jsx("span", {
|
|
16917
|
-
className: "navi_radio_field",
|
|
16918
|
-
children: jsxs("svg", {
|
|
16919
|
-
viewBox: "0 0 12 12",
|
|
16920
|
-
"aria-hidden": "true",
|
|
16921
|
-
preserveAspectRatio: "xMidYMid meet",
|
|
16922
|
-
children: [jsx("circle", {
|
|
16923
|
-
className: "navi_radio_border",
|
|
16924
|
-
cx: "6",
|
|
16925
|
-
cy: "6",
|
|
16926
|
-
r: "5.5",
|
|
16927
|
-
strokeWidth: "1"
|
|
16928
|
-
}), jsx("circle", {
|
|
16929
|
-
className: "navi_radio_dashed_border",
|
|
16930
|
-
cx: "6",
|
|
16931
|
-
cy: "6",
|
|
16932
|
-
r: "5.5",
|
|
16933
|
-
strokeWidth: "1",
|
|
16934
|
-
strokeDasharray: "2.16 2.16",
|
|
16935
|
-
strokeDashoffset: "0"
|
|
16936
|
-
}), jsx("circle", {
|
|
16937
|
-
className: "navi_radio_marker",
|
|
16938
|
-
cx: "6",
|
|
16939
|
-
cy: "6",
|
|
16940
|
-
r: "3.5"
|
|
16941
|
-
})]
|
|
16942
|
-
})
|
|
16943
|
-
})]
|
|
16812
|
+
color: "var(--loader-color)",
|
|
16813
|
+
inset: -1
|
|
16814
|
+
}), renderInputMemoized]
|
|
16944
16815
|
});
|
|
16945
16816
|
};
|
|
16946
|
-
const
|
|
16947
|
-
|
|
16817
|
+
const InputTextualWithAction = props => {
|
|
16818
|
+
const uiState = useContext(UIStateContext);
|
|
16819
|
+
const {
|
|
16820
|
+
action,
|
|
16821
|
+
loading,
|
|
16822
|
+
onCancel,
|
|
16823
|
+
onActionPrevented,
|
|
16824
|
+
onActionStart,
|
|
16825
|
+
onActionError,
|
|
16826
|
+
onActionEnd,
|
|
16827
|
+
cancelOnBlurInvalid,
|
|
16828
|
+
cancelOnEscape,
|
|
16829
|
+
actionErrorEffect,
|
|
16830
|
+
...rest
|
|
16831
|
+
} = props;
|
|
16832
|
+
const defaultRef = useRef();
|
|
16833
|
+
const ref = props.ref || defaultRef;
|
|
16834
|
+
const [boundAction] = useActionBoundToOneParam(action, uiState);
|
|
16835
|
+
const {
|
|
16836
|
+
loading: actionLoading
|
|
16837
|
+
} = useActionStatus(boundAction);
|
|
16838
|
+
const executeAction = useExecuteAction(ref, {
|
|
16839
|
+
errorEffect: actionErrorEffect
|
|
16840
|
+
});
|
|
16841
|
+
// here updating the input won't call the associated action
|
|
16842
|
+
// (user have to blur or press enter for this to happen)
|
|
16843
|
+
// so we can keep the ui state on cancel/abort/error and let user decide
|
|
16844
|
+
// to update ui state or retry via blur/enter as is
|
|
16845
|
+
useActionEvents(ref, {
|
|
16846
|
+
onCancel: (e, reason) => {
|
|
16847
|
+
if (reason.startsWith("blur_invalid")) {
|
|
16848
|
+
if (!cancelOnBlurInvalid) {
|
|
16849
|
+
return;
|
|
16850
|
+
}
|
|
16851
|
+
if (
|
|
16852
|
+
// error prevent cancellation until the user closes it (or something closes it)
|
|
16853
|
+
e.detail.failedConstraintInfo.level === "error" && e.detail.failedConstraintInfo.reportStatus !== "closed") {
|
|
16854
|
+
return;
|
|
16855
|
+
}
|
|
16856
|
+
}
|
|
16857
|
+
if (reason === "escape_key") {
|
|
16858
|
+
if (!cancelOnEscape) {
|
|
16859
|
+
return;
|
|
16860
|
+
}
|
|
16861
|
+
}
|
|
16862
|
+
onCancel?.(e, reason);
|
|
16863
|
+
},
|
|
16864
|
+
onRequested: e => {
|
|
16865
|
+
forwardActionRequested(e, boundAction);
|
|
16866
|
+
},
|
|
16867
|
+
onPrevented: onActionPrevented,
|
|
16868
|
+
onAction: executeAction,
|
|
16869
|
+
onStart: onActionStart,
|
|
16870
|
+
onError: onActionError,
|
|
16871
|
+
onEnd: onActionEnd
|
|
16872
|
+
});
|
|
16873
|
+
return jsx(InputTextualBasic, {
|
|
16874
|
+
"data-action": boundAction.name,
|
|
16875
|
+
...rest,
|
|
16876
|
+
ref: ref,
|
|
16877
|
+
loading: loading || actionLoading
|
|
16878
|
+
});
|
|
16879
|
+
};
|
|
16880
|
+
const InputTextualInsideForm = props => {
|
|
16881
|
+
const {
|
|
16882
|
+
// We destructure formContext to avoid passing it to the underlying input element
|
|
16883
|
+
// eslint-disable-next-line no-unused-vars
|
|
16884
|
+
formContext,
|
|
16885
|
+
...rest
|
|
16886
|
+
} = props;
|
|
16887
|
+
return jsx(InputTextualBasic, {
|
|
16888
|
+
...rest
|
|
16889
|
+
});
|
|
16948
16890
|
};
|
|
16949
|
-
const InputRadioInsideForm = InputRadio;
|
|
16950
|
-
|
|
16951
|
-
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
16952
|
-
@layer navi {
|
|
16953
|
-
.navi_input {
|
|
16954
|
-
--border-radius: 2px;
|
|
16955
|
-
--border-width: 1px;
|
|
16956
|
-
--outline-width: 1px;
|
|
16957
|
-
--outer-width: calc(var(--border-width) + var(--outline-width));
|
|
16958
16891
|
|
|
16959
|
-
|
|
16960
|
-
|
|
16961
|
-
|
|
16962
|
-
|
|
16963
|
-
|
|
16964
|
-
|
|
16965
|
-
|
|
16966
|
-
--placeholder-color: var(--color-dimmed);
|
|
16967
|
-
/* Hover */
|
|
16968
|
-
--border-color-hover: color-mix(in srgb, var(--border-color) 70%, black);
|
|
16969
|
-
--background-color-hover: color-mix(
|
|
16970
|
-
in srgb,
|
|
16971
|
-
var(--background-color) 95%,
|
|
16972
|
-
black
|
|
16973
|
-
);
|
|
16974
|
-
--color-hover: var(--color);
|
|
16975
|
-
/* Active */
|
|
16976
|
-
--border-color-active: color-mix(in srgb, var(--border-color) 90%, black);
|
|
16977
|
-
/* Readonly */
|
|
16978
|
-
--border-color-readonly: color-mix(
|
|
16979
|
-
in srgb,
|
|
16980
|
-
var(--border-color) 45%,
|
|
16981
|
-
transparent
|
|
16982
|
-
);
|
|
16983
|
-
--background-color-readonly: var(--background-color);
|
|
16984
|
-
--color-readonly: var(--color-dimmed);
|
|
16985
|
-
/* Disabled */
|
|
16986
|
-
--border-color-disabled: var(--border-color-readonly);
|
|
16987
|
-
--background-color-disabled: color-mix(
|
|
16988
|
-
in srgb,
|
|
16989
|
-
var(--background-color) 95%,
|
|
16990
|
-
grey
|
|
16991
|
-
);
|
|
16992
|
-
--color-disabled: color-mix(in srgb, var(--color) 95%, grey);
|
|
16993
|
-
}
|
|
16892
|
+
// As explained in https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/datetime-local#setting_timezones
|
|
16893
|
+
// datetime-local does not support timezones
|
|
16894
|
+
const convertToLocalTimezone = dateTimeString => {
|
|
16895
|
+
const date = new Date(dateTimeString);
|
|
16896
|
+
// Check if the date is valid
|
|
16897
|
+
if (isNaN(date.getTime())) {
|
|
16898
|
+
return dateTimeString;
|
|
16994
16899
|
}
|
|
16995
16900
|
|
|
16996
|
-
|
|
16997
|
-
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
|
|
17004
|
-
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
|
|
17008
|
-
|
|
17009
|
-
|
|
17010
|
-
|
|
17011
|
-
|
|
17012
|
-
|
|
17013
|
-
|
|
16901
|
+
// Format to YYYY-MM-DDThh:mm:ss
|
|
16902
|
+
const year = date.getFullYear();
|
|
16903
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
16904
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
16905
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
16906
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
16907
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
16908
|
+
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`;
|
|
16909
|
+
};
|
|
16910
|
+
/**
|
|
16911
|
+
* Converts a datetime string without timezone (local time) to UTC format with 'Z' notation
|
|
16912
|
+
*
|
|
16913
|
+
* @param {string} localDateTimeString - Local datetime string without timezone (e.g., "2023-07-15T14:30:00")
|
|
16914
|
+
* @returns {string} Datetime string in UTC with 'Z' notation (e.g., "2023-07-15T12:30:00Z")
|
|
16915
|
+
*/
|
|
16916
|
+
const convertToUTCTimezone = localDateTimeString => {
|
|
16917
|
+
if (!localDateTimeString) {
|
|
16918
|
+
return localDateTimeString;
|
|
17014
16919
|
}
|
|
16920
|
+
try {
|
|
16921
|
+
// Create a Date object using the local time string
|
|
16922
|
+
// The browser will interpret this as local timezone
|
|
16923
|
+
const localDate = new Date(localDateTimeString);
|
|
17015
16924
|
|
|
17016
|
-
|
|
17017
|
-
|
|
17018
|
-
|
|
17019
|
-
|
|
17020
|
-
|
|
17021
|
-
|
|
17022
|
-
|
|
17023
|
-
|
|
17024
|
-
|
|
17025
|
-
|
|
17026
|
-
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
border-style: solid;
|
|
17030
|
-
border-color: transparent;
|
|
17031
|
-
border-radius: var(--x-border-radius);
|
|
17032
|
-
outline-width: var(--x-border-width);
|
|
17033
|
-
outline-style: solid;
|
|
17034
|
-
outline-color: var(--x-border-color);
|
|
17035
|
-
outline-offset: calc(-1 * (var(--x-border-width)));
|
|
17036
|
-
}
|
|
17037
|
-
.navi_input .navi_native_input::placeholder {
|
|
17038
|
-
color: var(--x-placeholder-color);
|
|
17039
|
-
}
|
|
17040
|
-
.navi_input .navi_native_input:-internal-autofill-selected {
|
|
17041
|
-
/* Webkit is putting some nasty styles after automplete that look as follow */
|
|
17042
|
-
/* input:-internal-autofill-selected { color: FieldText !important; } */
|
|
17043
|
-
/* Fortunately we can override it as follow */
|
|
17044
|
-
-webkit-text-fill-color: var(--x-color) !important;
|
|
17045
|
-
}
|
|
17046
|
-
/* Readonly */
|
|
17047
|
-
.navi_input[data-readonly] {
|
|
17048
|
-
--x-border-color: var(--border-color-readonly);
|
|
17049
|
-
--x-background-color: var(--background-color-readonly);
|
|
17050
|
-
--x-color: var(--color-readonly);
|
|
17051
|
-
}
|
|
17052
|
-
/* Focus */
|
|
17053
|
-
.navi_input[data-focus] .navi_native_input,
|
|
17054
|
-
.navi_input[data-focus-visible] .navi_native_input {
|
|
17055
|
-
outline-width: var(--x-outer-width);
|
|
17056
|
-
outline-offset: calc(-1 * var(--x-outer-width));
|
|
17057
|
-
--x-border-color: var(--x-outline-color);
|
|
16925
|
+
// Check if the date is valid
|
|
16926
|
+
if (isNaN(localDate.getTime())) {
|
|
16927
|
+
return localDateTimeString;
|
|
16928
|
+
}
|
|
16929
|
+
|
|
16930
|
+
// Convert to UTC ISO string
|
|
16931
|
+
const utcString = localDate.toISOString();
|
|
16932
|
+
|
|
16933
|
+
// Return the UTC string (which includes the 'Z' notation)
|
|
16934
|
+
return utcString;
|
|
16935
|
+
} catch (error) {
|
|
16936
|
+
console.error("Error converting local datetime to UTC:", error);
|
|
16937
|
+
return localDateTimeString;
|
|
17058
16938
|
}
|
|
17059
|
-
|
|
17060
|
-
|
|
17061
|
-
|
|
17062
|
-
|
|
17063
|
-
|
|
16939
|
+
};
|
|
16940
|
+
|
|
16941
|
+
const Input = forwardRef((props, ref) => {
|
|
16942
|
+
const {
|
|
16943
|
+
type
|
|
16944
|
+
} = props;
|
|
16945
|
+
if (type === "radio") {
|
|
16946
|
+
return jsx(InputRadio, {
|
|
16947
|
+
...props,
|
|
16948
|
+
ref: ref
|
|
16949
|
+
});
|
|
17064
16950
|
}
|
|
17065
|
-
|
|
17066
|
-
|
|
17067
|
-
|
|
16951
|
+
if (type === "checkbox") {
|
|
16952
|
+
return jsx(InputCheckbox, {
|
|
16953
|
+
...props,
|
|
16954
|
+
ref: ref
|
|
16955
|
+
});
|
|
17068
16956
|
}
|
|
17069
|
-
|
|
17070
|
-
|
|
17071
|
-
|
|
17072
|
-
const uiState = useUIState(uiStateController);
|
|
17073
|
-
const input = renderActionableComponent(props, {
|
|
17074
|
-
Basic: InputTextualBasic,
|
|
17075
|
-
WithAction: InputTextualWithAction,
|
|
17076
|
-
InsideForm: InputTextualInsideForm
|
|
17077
|
-
});
|
|
17078
|
-
return jsx(UIStateControllerContext.Provider, {
|
|
17079
|
-
value: uiStateController,
|
|
17080
|
-
children: jsx(UIStateContext.Provider, {
|
|
17081
|
-
value: uiState,
|
|
17082
|
-
children: input
|
|
17083
|
-
})
|
|
16957
|
+
return jsx(InputTextual, {
|
|
16958
|
+
...props,
|
|
16959
|
+
ref: ref
|
|
17084
16960
|
});
|
|
17085
|
-
};
|
|
17086
|
-
|
|
17087
|
-
|
|
17088
|
-
|
|
17089
|
-
|
|
17090
|
-
|
|
17091
|
-
"paddingRight": "--padding-right",
|
|
17092
|
-
"paddingBottom": "--padding-bottom",
|
|
17093
|
-
"paddingLeft": "--padding-left",
|
|
17094
|
-
"backgroundColor": "--background-color",
|
|
17095
|
-
"borderColor": "--border-color",
|
|
17096
|
-
"color": "--color",
|
|
17097
|
-
":hover": {
|
|
17098
|
-
backgroundColor: "--background-color-hover",
|
|
17099
|
-
borderColor: "--border-color-hover",
|
|
17100
|
-
color: "--color-hover"
|
|
17101
|
-
},
|
|
17102
|
-
":active": {
|
|
17103
|
-
borderColor: "--border-color-active"
|
|
17104
|
-
},
|
|
17105
|
-
":read-only": {
|
|
17106
|
-
backgroundColor: "--background-color-readonly",
|
|
17107
|
-
borderColor: "--border-color-readonly",
|
|
17108
|
-
color: "--color-readonly"
|
|
17109
|
-
},
|
|
17110
|
-
":disabled": {
|
|
17111
|
-
backgroundColor: "--background-color-disabled",
|
|
17112
|
-
borderColor: "--border-color-disabled",
|
|
17113
|
-
color: "--color-disabled"
|
|
16961
|
+
});
|
|
16962
|
+
|
|
16963
|
+
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
16964
|
+
.navi_editable_wrapper {
|
|
16965
|
+
position: absolute;
|
|
16966
|
+
inset: 0;
|
|
17114
16967
|
}
|
|
16968
|
+
`;
|
|
16969
|
+
const useEditionController = () => {
|
|
16970
|
+
const [editing, editingSetter] = useState(null);
|
|
16971
|
+
const startEditing = useCallback(event => {
|
|
16972
|
+
editingSetter(current => {
|
|
16973
|
+
return current || {
|
|
16974
|
+
event
|
|
16975
|
+
};
|
|
16976
|
+
});
|
|
16977
|
+
}, []);
|
|
16978
|
+
const stopEditing = useCallback(() => {
|
|
16979
|
+
editingSetter(null);
|
|
16980
|
+
}, []);
|
|
16981
|
+
const prevEditingRef = useRef(editing);
|
|
16982
|
+
const editionJustEnded = prevEditingRef.current && !editing;
|
|
16983
|
+
prevEditingRef.current = editing;
|
|
16984
|
+
return {
|
|
16985
|
+
editing,
|
|
16986
|
+
startEditing,
|
|
16987
|
+
stopEditing,
|
|
16988
|
+
editionJustEnded
|
|
16989
|
+
};
|
|
17115
16990
|
};
|
|
17116
|
-
const
|
|
17117
|
-
|
|
17118
|
-
|
|
17119
|
-
|
|
17120
|
-
|
|
17121
|
-
|
|
17122
|
-
|
|
17123
|
-
|
|
17124
|
-
|
|
17125
|
-
|
|
17126
|
-
const {
|
|
16991
|
+
const Editable = forwardRef((props, ref) => {
|
|
16992
|
+
let {
|
|
16993
|
+
children,
|
|
16994
|
+
action,
|
|
16995
|
+
editing,
|
|
16996
|
+
name,
|
|
16997
|
+
value,
|
|
16998
|
+
valueSignal,
|
|
16999
|
+
onEditEnd,
|
|
17000
|
+
constraints,
|
|
17127
17001
|
type,
|
|
17128
|
-
|
|
17002
|
+
required,
|
|
17003
|
+
readOnly,
|
|
17004
|
+
min,
|
|
17005
|
+
max,
|
|
17006
|
+
step,
|
|
17007
|
+
minLength,
|
|
17008
|
+
maxLength,
|
|
17009
|
+
pattern,
|
|
17010
|
+
wrapperProps,
|
|
17011
|
+
autoSelect = true,
|
|
17012
|
+
width,
|
|
17013
|
+
height,
|
|
17014
|
+
...rest
|
|
17015
|
+
} = props;
|
|
17016
|
+
const innerRef = useRef();
|
|
17017
|
+
useImperativeHandle(ref, () => innerRef.current);
|
|
17018
|
+
if (valueSignal) {
|
|
17019
|
+
value = valueSignal.value;
|
|
17020
|
+
}
|
|
17021
|
+
const editingPreviousRef = useRef(editing);
|
|
17022
|
+
const valueWhenEditStartRef = useRef(editing ? value : undefined);
|
|
17023
|
+
if (editingPreviousRef.current !== editing) {
|
|
17024
|
+
if (editing) {
|
|
17025
|
+
valueWhenEditStartRef.current = value; // Always store the external value
|
|
17026
|
+
}
|
|
17027
|
+
editingPreviousRef.current = editing;
|
|
17028
|
+
}
|
|
17029
|
+
|
|
17030
|
+
// Simulate typing the initial value when editing starts with a custom value
|
|
17031
|
+
useLayoutEffect(() => {
|
|
17032
|
+
if (!editing) {
|
|
17033
|
+
return;
|
|
17034
|
+
}
|
|
17035
|
+
const editingEvent = editing.event;
|
|
17036
|
+
if (!editingEvent) {
|
|
17037
|
+
return;
|
|
17038
|
+
}
|
|
17039
|
+
const editingEventInitialValue = editingEvent.detail?.initialValue;
|
|
17040
|
+
if (editingEventInitialValue === undefined) {
|
|
17041
|
+
return;
|
|
17042
|
+
}
|
|
17043
|
+
const input = innerRef.current;
|
|
17044
|
+
input.value = editingEventInitialValue;
|
|
17045
|
+
input.dispatchEvent(new CustomEvent("input", {
|
|
17046
|
+
bubbles: false
|
|
17047
|
+
}));
|
|
17048
|
+
}, [editing]);
|
|
17049
|
+
const input = jsx(Input, {
|
|
17050
|
+
ref: innerRef,
|
|
17051
|
+
...rest,
|
|
17052
|
+
type: type,
|
|
17053
|
+
name: name,
|
|
17054
|
+
value: value,
|
|
17055
|
+
valueSignal: valueSignal,
|
|
17056
|
+
autoFocus: true,
|
|
17057
|
+
autoFocusVisible: true,
|
|
17058
|
+
autoSelect: autoSelect,
|
|
17059
|
+
cancelOnEscape: true,
|
|
17060
|
+
cancelOnBlurInvalid: true,
|
|
17061
|
+
constraints: constraints,
|
|
17062
|
+
required: required,
|
|
17063
|
+
readOnly: readOnly,
|
|
17064
|
+
min: min,
|
|
17065
|
+
max: max,
|
|
17066
|
+
step: step,
|
|
17067
|
+
minLength: minLength,
|
|
17068
|
+
maxLength: maxLength,
|
|
17069
|
+
pattern: pattern,
|
|
17070
|
+
width: width,
|
|
17071
|
+
height: height,
|
|
17072
|
+
onCancel: e => {
|
|
17073
|
+
if (valueSignal) {
|
|
17074
|
+
valueSignal.value = valueWhenEditStartRef.current;
|
|
17075
|
+
}
|
|
17076
|
+
onEditEnd({
|
|
17077
|
+
cancelled: true,
|
|
17078
|
+
event: e
|
|
17079
|
+
});
|
|
17080
|
+
},
|
|
17081
|
+
onBlur: e => {
|
|
17082
|
+
const value = type === "number" ? e.target.valueAsNumber : e.target.value;
|
|
17083
|
+
const valueWhenEditStart = valueWhenEditStartRef.current;
|
|
17084
|
+
if (value === valueWhenEditStart) {
|
|
17085
|
+
onEditEnd({
|
|
17086
|
+
cancelled: true,
|
|
17087
|
+
event: e
|
|
17088
|
+
});
|
|
17089
|
+
return;
|
|
17090
|
+
}
|
|
17091
|
+
},
|
|
17092
|
+
action: action || (() => {}),
|
|
17093
|
+
onActionEnd: e => {
|
|
17094
|
+
onEditEnd({
|
|
17095
|
+
success: true,
|
|
17096
|
+
event: e
|
|
17097
|
+
});
|
|
17098
|
+
}
|
|
17099
|
+
});
|
|
17100
|
+
return jsxs(Fragment, {
|
|
17101
|
+
children: [children || jsx("span", {
|
|
17102
|
+
children: value
|
|
17103
|
+
}), editing && jsx("div", {
|
|
17104
|
+
...wrapperProps,
|
|
17105
|
+
className: ["navi_editable_wrapper", ...(wrapperProps?.className || "").split(" ")].join(" "),
|
|
17106
|
+
children: input
|
|
17107
|
+
})]
|
|
17108
|
+
});
|
|
17109
|
+
});
|
|
17110
|
+
|
|
17111
|
+
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
17112
|
+
@layer navi {
|
|
17113
|
+
.navi_checkbox_list {
|
|
17114
|
+
display: flex;
|
|
17115
|
+
flex-direction: column;
|
|
17116
|
+
}
|
|
17117
|
+
}
|
|
17118
|
+
`;
|
|
17119
|
+
const CheckboxList = forwardRef((props, ref) => {
|
|
17120
|
+
const uiStateController = useUIGroupStateController(props, "checkbox_list", {
|
|
17121
|
+
childComponentType: "checkbox",
|
|
17122
|
+
aggregateChildStates: childUIStateControllers => {
|
|
17123
|
+
const values = [];
|
|
17124
|
+
for (const childUIStateController of childUIStateControllers) {
|
|
17125
|
+
if (childUIStateController.uiState) {
|
|
17126
|
+
values.push(childUIStateController.uiState);
|
|
17127
|
+
}
|
|
17128
|
+
}
|
|
17129
|
+
return values.length === 0 ? undefined : values;
|
|
17130
|
+
}
|
|
17131
|
+
});
|
|
17132
|
+
const uiState = useUIState(uiStateController);
|
|
17133
|
+
const checkboxList = renderActionableComponent(props, ref);
|
|
17134
|
+
return jsx(UIStateControllerContext.Provider, {
|
|
17135
|
+
value: uiStateController,
|
|
17136
|
+
children: jsx(UIStateContext.Provider, {
|
|
17137
|
+
value: uiState,
|
|
17138
|
+
children: checkboxList
|
|
17139
|
+
})
|
|
17140
|
+
});
|
|
17141
|
+
});
|
|
17142
|
+
const Checkbox = InputCheckbox;
|
|
17143
|
+
const CheckboxListBasic = forwardRef((props, ref) => {
|
|
17144
|
+
const contextReadOnly = useContext(ReadOnlyContext);
|
|
17145
|
+
const contextDisabled = useContext(DisabledContext);
|
|
17146
|
+
const contextLoading = useContext(LoadingContext);
|
|
17147
|
+
const uiStateController = useContext(UIStateControllerContext);
|
|
17148
|
+
const {
|
|
17149
|
+
name,
|
|
17129
17150
|
readOnly,
|
|
17130
17151
|
disabled,
|
|
17131
|
-
|
|
17152
|
+
required,
|
|
17132
17153
|
loading,
|
|
17133
|
-
|
|
17134
|
-
autoFocusVisible,
|
|
17135
|
-
autoSelect,
|
|
17154
|
+
children,
|
|
17136
17155
|
...rest
|
|
17137
17156
|
} = props;
|
|
17138
|
-
const
|
|
17139
|
-
|
|
17140
|
-
const
|
|
17141
|
-
const innerLoading = loading || contextLoading && contextLoadingElement === ref.current;
|
|
17157
|
+
const innerRef = useRef();
|
|
17158
|
+
useImperativeHandle(ref, () => innerRef.current);
|
|
17159
|
+
const innerLoading = loading || contextLoading;
|
|
17142
17160
|
const innerReadOnly = readOnly || contextReadOnly || innerLoading || uiStateController.readOnly;
|
|
17143
17161
|
const innerDisabled = disabled || contextDisabled;
|
|
17144
|
-
|
|
17145
|
-
reportReadOnlyOnLabel?.(innerReadOnly);
|
|
17146
|
-
useAutoFocus(ref, autoFocus, {
|
|
17147
|
-
autoFocusVisible,
|
|
17148
|
-
autoSelect
|
|
17149
|
-
});
|
|
17150
|
-
useConstraints(ref, constraints);
|
|
17151
|
-
const innerOnInput = useStableCallback(onInput);
|
|
17152
|
-
const renderInput = inputProps => {
|
|
17153
|
-
return jsx(Box, {
|
|
17154
|
-
...inputProps,
|
|
17155
|
-
as: "input",
|
|
17156
|
-
ref: ref,
|
|
17157
|
-
type: type,
|
|
17158
|
-
"data-value": uiState,
|
|
17159
|
-
value: innerValue,
|
|
17160
|
-
onInput: e => {
|
|
17161
|
-
let inputValue;
|
|
17162
|
-
if (type === "number") {
|
|
17163
|
-
inputValue = e.target.valueAsNumber;
|
|
17164
|
-
} else if (type === "datetime-local") {
|
|
17165
|
-
inputValue = convertToUTCTimezone(e.target.value);
|
|
17166
|
-
} else {
|
|
17167
|
-
inputValue = e.target.value;
|
|
17168
|
-
}
|
|
17169
|
-
uiStateController.setUIState(inputValue, e);
|
|
17170
|
-
innerOnInput?.(e);
|
|
17171
|
-
},
|
|
17172
|
-
onresetuistate: e => {
|
|
17173
|
-
uiStateController.resetUIState(e);
|
|
17174
|
-
},
|
|
17175
|
-
onsetuistate: e => {
|
|
17176
|
-
uiStateController.setUIState(e.detail.value, e);
|
|
17177
|
-
}
|
|
17178
|
-
// style management
|
|
17179
|
-
,
|
|
17180
|
-
baseClassName: "navi_native_input"
|
|
17181
|
-
});
|
|
17182
|
-
};
|
|
17183
|
-
const renderInputMemoized = useCallback(renderInput, [type, uiState, innerValue, innerOnInput]);
|
|
17184
|
-
return jsxs(Box, {
|
|
17185
|
-
as: "span",
|
|
17186
|
-
box: true,
|
|
17187
|
-
baseClassName: "navi_input",
|
|
17188
|
-
styleCSSVars: InputStyleCSSVars,
|
|
17189
|
-
pseudoStateSelector: ".navi_native_input",
|
|
17190
|
-
visualSelector: ".navi_native_input",
|
|
17191
|
-
basePseudoState: {
|
|
17192
|
-
":read-only": innerReadOnly,
|
|
17193
|
-
":disabled": innerDisabled,
|
|
17194
|
-
":-navi-loading": innerLoading
|
|
17195
|
-
},
|
|
17196
|
-
pseudoClasses: InputPseudoClasses,
|
|
17197
|
-
pseudoElements: InputPseudoElements,
|
|
17198
|
-
hasChildFunction: true,
|
|
17162
|
+
return jsx("div", {
|
|
17199
17163
|
...rest,
|
|
17200
|
-
|
|
17201
|
-
|
|
17202
|
-
|
|
17203
|
-
|
|
17204
|
-
|
|
17164
|
+
ref: innerRef,
|
|
17165
|
+
name: name,
|
|
17166
|
+
className: "navi_checkbox_list",
|
|
17167
|
+
"data-checkbox-list": true
|
|
17168
|
+
// eslint-disable-next-line react/no-unknown-property
|
|
17169
|
+
,
|
|
17170
|
+
onresetuistate: e => {
|
|
17171
|
+
uiStateController.resetUIState(e);
|
|
17172
|
+
},
|
|
17173
|
+
children: jsx(ParentUIStateControllerContext.Provider, {
|
|
17174
|
+
value: uiStateController,
|
|
17175
|
+
children: jsx(FieldNameContext.Provider, {
|
|
17176
|
+
value: name,
|
|
17177
|
+
children: jsx(ReadOnlyContext.Provider, {
|
|
17178
|
+
value: innerReadOnly,
|
|
17179
|
+
children: jsx(DisabledContext.Provider, {
|
|
17180
|
+
value: innerDisabled,
|
|
17181
|
+
children: jsx(RequiredContext.Provider, {
|
|
17182
|
+
value: required,
|
|
17183
|
+
children: jsx(LoadingContext.Provider, {
|
|
17184
|
+
value: innerLoading,
|
|
17185
|
+
children: children
|
|
17186
|
+
})
|
|
17187
|
+
})
|
|
17188
|
+
})
|
|
17189
|
+
})
|
|
17190
|
+
})
|
|
17191
|
+
})
|
|
17205
17192
|
});
|
|
17206
|
-
};
|
|
17207
|
-
|
|
17193
|
+
});
|
|
17194
|
+
forwardRef((props, ref) => {
|
|
17195
|
+
const uiStateController = useContext(UIStateControllerContext);
|
|
17208
17196
|
const uiState = useContext(UIStateContext);
|
|
17209
17197
|
const {
|
|
17210
17198
|
action,
|
|
17211
|
-
|
|
17199
|
+
actionErrorEffect,
|
|
17212
17200
|
onCancel,
|
|
17213
17201
|
onActionPrevented,
|
|
17214
17202
|
onActionStart,
|
|
17203
|
+
onActionAbort,
|
|
17215
17204
|
onActionError,
|
|
17216
17205
|
onActionEnd,
|
|
17217
|
-
|
|
17218
|
-
|
|
17219
|
-
actionErrorEffect,
|
|
17206
|
+
loading,
|
|
17207
|
+
children,
|
|
17220
17208
|
...rest
|
|
17221
17209
|
} = props;
|
|
17222
|
-
const
|
|
17223
|
-
|
|
17224
|
-
const [boundAction] =
|
|
17210
|
+
const innerRef = useRef();
|
|
17211
|
+
useImperativeHandle(ref, () => innerRef.current);
|
|
17212
|
+
const [boundAction] = useActionBoundToOneArrayParam(action, uiState);
|
|
17225
17213
|
const {
|
|
17226
17214
|
loading: actionLoading
|
|
17227
17215
|
} = useActionStatus(boundAction);
|
|
17228
|
-
const executeAction = useExecuteAction(
|
|
17216
|
+
const executeAction = useExecuteAction(innerRef, {
|
|
17229
17217
|
errorEffect: actionErrorEffect
|
|
17230
17218
|
});
|
|
17231
|
-
|
|
17232
|
-
|
|
17233
|
-
// so we can keep the ui state on cancel/abort/error and let user decide
|
|
17234
|
-
// to update ui state or retry via blur/enter as is
|
|
17235
|
-
useActionEvents(ref, {
|
|
17219
|
+
const [actionRequester, setActionRequester] = useState(null);
|
|
17220
|
+
useActionEvents(innerRef, {
|
|
17236
17221
|
onCancel: (e, reason) => {
|
|
17237
|
-
|
|
17238
|
-
if (!cancelOnBlurInvalid) {
|
|
17239
|
-
return;
|
|
17240
|
-
}
|
|
17241
|
-
if (
|
|
17242
|
-
// error prevent cancellation until the user closes it (or something closes it)
|
|
17243
|
-
e.detail.failedConstraintInfo.level === "error" && e.detail.failedConstraintInfo.reportStatus !== "closed") {
|
|
17244
|
-
return;
|
|
17245
|
-
}
|
|
17246
|
-
}
|
|
17247
|
-
if (reason === "escape_key") {
|
|
17248
|
-
if (!cancelOnEscape) {
|
|
17249
|
-
return;
|
|
17250
|
-
}
|
|
17251
|
-
}
|
|
17222
|
+
uiStateController.resetUIState(e);
|
|
17252
17223
|
onCancel?.(e, reason);
|
|
17253
17224
|
},
|
|
17254
|
-
onRequested: e => {
|
|
17255
|
-
forwardActionRequested(e, boundAction);
|
|
17256
|
-
},
|
|
17257
17225
|
onPrevented: onActionPrevented,
|
|
17258
|
-
onAction:
|
|
17226
|
+
onAction: actionEvent => {
|
|
17227
|
+
setActionRequester(actionEvent.detail.requester);
|
|
17228
|
+
executeAction(actionEvent);
|
|
17229
|
+
},
|
|
17259
17230
|
onStart: onActionStart,
|
|
17260
|
-
|
|
17261
|
-
|
|
17231
|
+
onAbort: e => {
|
|
17232
|
+
uiStateController.resetUIState(e);
|
|
17233
|
+
onActionAbort?.(e);
|
|
17234
|
+
},
|
|
17235
|
+
onError: e => {
|
|
17236
|
+
uiStateController.resetUIState(e);
|
|
17237
|
+
onActionError?.(e);
|
|
17238
|
+
},
|
|
17239
|
+
onEnd: e => {
|
|
17240
|
+
onActionEnd?.(e);
|
|
17241
|
+
}
|
|
17262
17242
|
});
|
|
17263
|
-
return jsx(
|
|
17243
|
+
return jsx(CheckboxListBasic, {
|
|
17264
17244
|
"data-action": boundAction.name,
|
|
17265
17245
|
...rest,
|
|
17266
|
-
ref:
|
|
17267
|
-
|
|
17268
|
-
|
|
17269
|
-
|
|
17270
|
-
|
|
17271
|
-
|
|
17272
|
-
|
|
17273
|
-
|
|
17274
|
-
|
|
17275
|
-
|
|
17276
|
-
|
|
17277
|
-
|
|
17278
|
-
|
|
17246
|
+
ref: innerRef,
|
|
17247
|
+
onChange: event => {
|
|
17248
|
+
const checkboxList = innerRef.current;
|
|
17249
|
+
const checkbox = event.target;
|
|
17250
|
+
requestAction(checkboxList, boundAction, {
|
|
17251
|
+
event,
|
|
17252
|
+
requester: checkbox
|
|
17253
|
+
});
|
|
17254
|
+
},
|
|
17255
|
+
loading: loading || actionLoading,
|
|
17256
|
+
children: jsx(LoadingElementContext.Provider, {
|
|
17257
|
+
value: actionRequester,
|
|
17258
|
+
children: children
|
|
17259
|
+
})
|
|
17279
17260
|
});
|
|
17280
|
-
};
|
|
17261
|
+
});
|
|
17281
17262
|
|
|
17282
|
-
|
|
17283
|
-
|
|
17284
|
-
|
|
17285
|
-
|
|
17286
|
-
|
|
17287
|
-
|
|
17288
|
-
|
|
17263
|
+
const collectFormElementValues = (element) => {
|
|
17264
|
+
let formElements;
|
|
17265
|
+
if (element.tagName === "FORM") {
|
|
17266
|
+
formElements = element.elements;
|
|
17267
|
+
} else {
|
|
17268
|
+
// fieldset or anything else
|
|
17269
|
+
formElements = element.querySelectorAll(
|
|
17270
|
+
"input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button[name]:not([disabled])",
|
|
17271
|
+
);
|
|
17289
17272
|
}
|
|
17290
17273
|
|
|
17291
|
-
|
|
17292
|
-
const
|
|
17293
|
-
const
|
|
17294
|
-
|
|
17295
|
-
|
|
17296
|
-
|
|
17297
|
-
|
|
17298
|
-
|
|
17299
|
-
|
|
17300
|
-
|
|
17301
|
-
|
|
17302
|
-
|
|
17303
|
-
|
|
17304
|
-
|
|
17305
|
-
|
|
17306
|
-
|
|
17307
|
-
|
|
17308
|
-
|
|
17274
|
+
const values = {};
|
|
17275
|
+
const checkboxArrayNameSet = new Set();
|
|
17276
|
+
for (const formElement of formElements) {
|
|
17277
|
+
if (formElement.type === "checkbox" && formElement.name) {
|
|
17278
|
+
const name = formElement.name;
|
|
17279
|
+
const endsWithBrackets = name.endsWith("[]");
|
|
17280
|
+
if (endsWithBrackets) {
|
|
17281
|
+
checkboxArrayNameSet.add(name);
|
|
17282
|
+
values[name] = [];
|
|
17283
|
+
continue;
|
|
17284
|
+
}
|
|
17285
|
+
const closestDataCheckboxList = formElement.closest(
|
|
17286
|
+
"[data-checkbox-list]",
|
|
17287
|
+
);
|
|
17288
|
+
if (closestDataCheckboxList) {
|
|
17289
|
+
checkboxArrayNameSet.add(name);
|
|
17290
|
+
values[name] = [];
|
|
17291
|
+
}
|
|
17292
|
+
}
|
|
17309
17293
|
}
|
|
17310
|
-
try {
|
|
17311
|
-
// Create a Date object using the local time string
|
|
17312
|
-
// The browser will interpret this as local timezone
|
|
17313
|
-
const localDate = new Date(localDateTimeString);
|
|
17314
17294
|
|
|
17315
|
-
|
|
17316
|
-
|
|
17317
|
-
|
|
17295
|
+
for (const formElement of formElements) {
|
|
17296
|
+
const name = formElement.name;
|
|
17297
|
+
if (!name) {
|
|
17298
|
+
continue;
|
|
17299
|
+
}
|
|
17300
|
+
const value = getFormElementValue(formElement);
|
|
17301
|
+
if (value === undefined) {
|
|
17302
|
+
continue; // Skip unchecked checkboxes/radios
|
|
17303
|
+
}
|
|
17304
|
+
if (formElement.type === "checkbox" && checkboxArrayNameSet.has(name)) {
|
|
17305
|
+
values[name].push(value);
|
|
17306
|
+
} else {
|
|
17307
|
+
values[name] = value;
|
|
17318
17308
|
}
|
|
17309
|
+
}
|
|
17310
|
+
return values;
|
|
17311
|
+
};
|
|
17319
17312
|
|
|
17320
|
-
|
|
17321
|
-
|
|
17313
|
+
const getFormElementValue = (formElement) => {
|
|
17314
|
+
const { type, tagName } = formElement;
|
|
17322
17315
|
|
|
17323
|
-
|
|
17324
|
-
|
|
17325
|
-
|
|
17326
|
-
|
|
17327
|
-
|
|
17316
|
+
if (tagName === "SELECT") {
|
|
17317
|
+
if (formElement.multiple) {
|
|
17318
|
+
return Array.from(formElement.selectedOptions, (option) =>
|
|
17319
|
+
getValue(option),
|
|
17320
|
+
);
|
|
17321
|
+
}
|
|
17322
|
+
return formElement.value;
|
|
17328
17323
|
}
|
|
17329
|
-
};
|
|
17330
17324
|
|
|
17331
|
-
|
|
17332
|
-
|
|
17333
|
-
type
|
|
17334
|
-
} = props;
|
|
17335
|
-
if (type === "radio") {
|
|
17336
|
-
return jsx(InputRadio, {
|
|
17337
|
-
...props,
|
|
17338
|
-
ref: ref
|
|
17339
|
-
});
|
|
17325
|
+
if (type === "checkbox" || type === "radio") {
|
|
17326
|
+
return formElement.checked ? getValue(formElement) : undefined;
|
|
17340
17327
|
}
|
|
17341
|
-
|
|
17342
|
-
|
|
17343
|
-
|
|
17344
|
-
ref: ref
|
|
17345
|
-
});
|
|
17328
|
+
|
|
17329
|
+
if (type === "file") {
|
|
17330
|
+
return formElement.files; // Return FileList for special handling
|
|
17346
17331
|
}
|
|
17347
|
-
return jsx(InputTextual, {
|
|
17348
|
-
...props,
|
|
17349
|
-
ref: ref
|
|
17350
|
-
});
|
|
17351
|
-
});
|
|
17352
17332
|
|
|
17353
|
-
|
|
17354
|
-
|
|
17355
|
-
|
|
17356
|
-
|
|
17333
|
+
return getValue(formElement);
|
|
17334
|
+
};
|
|
17335
|
+
|
|
17336
|
+
const getValue = (formElement) => {
|
|
17337
|
+
const hasDataValueAttribute = formElement.hasAttribute("data-value");
|
|
17338
|
+
if (hasDataValueAttribute) {
|
|
17339
|
+
// happens for "datetime-local" inputs to keep the timezone
|
|
17340
|
+
// consistent when sending to the server
|
|
17341
|
+
return formElement.getAttribute("data-value");
|
|
17357
17342
|
}
|
|
17358
|
-
|
|
17359
|
-
const useEditionController = () => {
|
|
17360
|
-
const [editing, editingSetter] = useState(null);
|
|
17361
|
-
const startEditing = useCallback(event => {
|
|
17362
|
-
editingSetter(current => {
|
|
17363
|
-
return current || {
|
|
17364
|
-
event
|
|
17365
|
-
};
|
|
17366
|
-
});
|
|
17367
|
-
}, []);
|
|
17368
|
-
const stopEditing = useCallback(() => {
|
|
17369
|
-
editingSetter(null);
|
|
17370
|
-
}, []);
|
|
17371
|
-
const prevEditingRef = useRef(editing);
|
|
17372
|
-
const editionJustEnded = prevEditingRef.current && !editing;
|
|
17373
|
-
prevEditingRef.current = editing;
|
|
17374
|
-
return {
|
|
17375
|
-
editing,
|
|
17376
|
-
startEditing,
|
|
17377
|
-
stopEditing,
|
|
17378
|
-
editionJustEnded
|
|
17379
|
-
};
|
|
17343
|
+
return formElement.value;
|
|
17380
17344
|
};
|
|
17381
|
-
const Editable = forwardRef((props, ref) => {
|
|
17382
|
-
let {
|
|
17383
|
-
children,
|
|
17384
|
-
action,
|
|
17385
|
-
editing,
|
|
17386
|
-
name,
|
|
17387
|
-
value,
|
|
17388
|
-
valueSignal,
|
|
17389
|
-
onEditEnd,
|
|
17390
|
-
constraints,
|
|
17391
|
-
type,
|
|
17392
|
-
required,
|
|
17393
|
-
readOnly,
|
|
17394
|
-
min,
|
|
17395
|
-
max,
|
|
17396
|
-
step,
|
|
17397
|
-
minLength,
|
|
17398
|
-
maxLength,
|
|
17399
|
-
pattern,
|
|
17400
|
-
wrapperProps,
|
|
17401
|
-
autoSelect = true,
|
|
17402
|
-
width,
|
|
17403
|
-
height,
|
|
17404
|
-
...rest
|
|
17405
|
-
} = props;
|
|
17406
|
-
const innerRef = useRef();
|
|
17407
|
-
useImperativeHandle(ref, () => innerRef.current);
|
|
17408
|
-
if (valueSignal) {
|
|
17409
|
-
value = valueSignal.value;
|
|
17410
|
-
}
|
|
17411
|
-
const editingPreviousRef = useRef(editing);
|
|
17412
|
-
const valueWhenEditStartRef = useRef(editing ? value : undefined);
|
|
17413
|
-
if (editingPreviousRef.current !== editing) {
|
|
17414
|
-
if (editing) {
|
|
17415
|
-
valueWhenEditStartRef.current = value; // Always store the external value
|
|
17416
|
-
}
|
|
17417
|
-
editingPreviousRef.current = editing;
|
|
17418
|
-
}
|
|
17419
17345
|
|
|
17420
|
-
|
|
17421
|
-
|
|
17422
|
-
|
|
17423
|
-
|
|
17424
|
-
|
|
17425
|
-
|
|
17426
|
-
|
|
17427
|
-
|
|
17428
|
-
|
|
17429
|
-
|
|
17430
|
-
|
|
17431
|
-
|
|
17432
|
-
|
|
17433
|
-
|
|
17434
|
-
input.value = editingEventInitialValue;
|
|
17435
|
-
input.dispatchEvent(new CustomEvent("input", {
|
|
17436
|
-
bubbles: false
|
|
17437
|
-
}));
|
|
17438
|
-
}, [editing]);
|
|
17439
|
-
const input = jsx(Input, {
|
|
17440
|
-
ref: innerRef,
|
|
17441
|
-
...rest,
|
|
17442
|
-
type: type,
|
|
17443
|
-
name: name,
|
|
17444
|
-
value: value,
|
|
17445
|
-
valueSignal: valueSignal,
|
|
17446
|
-
autoFocus: true,
|
|
17447
|
-
autoFocusVisible: true,
|
|
17448
|
-
autoSelect: autoSelect,
|
|
17449
|
-
cancelOnEscape: true,
|
|
17450
|
-
cancelOnBlurInvalid: true,
|
|
17451
|
-
constraints: constraints,
|
|
17452
|
-
required: required,
|
|
17453
|
-
readOnly: readOnly,
|
|
17454
|
-
min: min,
|
|
17455
|
-
max: max,
|
|
17456
|
-
step: step,
|
|
17457
|
-
minLength: minLength,
|
|
17458
|
-
maxLength: maxLength,
|
|
17459
|
-
pattern: pattern,
|
|
17460
|
-
width: width,
|
|
17461
|
-
height: height,
|
|
17462
|
-
onCancel: e => {
|
|
17463
|
-
if (valueSignal) {
|
|
17464
|
-
valueSignal.value = valueWhenEditStartRef.current;
|
|
17465
|
-
}
|
|
17466
|
-
onEditEnd({
|
|
17467
|
-
cancelled: true,
|
|
17468
|
-
event: e
|
|
17469
|
-
});
|
|
17470
|
-
},
|
|
17471
|
-
onBlur: e => {
|
|
17472
|
-
const value = type === "number" ? e.target.valueAsNumber : e.target.value;
|
|
17473
|
-
const valueWhenEditStart = valueWhenEditStartRef.current;
|
|
17474
|
-
if (value === valueWhenEditStart) {
|
|
17475
|
-
onEditEnd({
|
|
17476
|
-
cancelled: true,
|
|
17477
|
-
event: e
|
|
17478
|
-
});
|
|
17479
|
-
return;
|
|
17480
|
-
}
|
|
17481
|
-
},
|
|
17482
|
-
action: action || (() => {}),
|
|
17483
|
-
onActionEnd: e => {
|
|
17484
|
-
onEditEnd({
|
|
17485
|
-
success: true,
|
|
17486
|
-
event: e
|
|
17487
|
-
});
|
|
17488
|
-
}
|
|
17489
|
-
});
|
|
17490
|
-
return jsxs(Fragment, {
|
|
17491
|
-
children: [children || jsx("span", {
|
|
17492
|
-
children: value
|
|
17493
|
-
}), editing && jsx("div", {
|
|
17494
|
-
...wrapperProps,
|
|
17495
|
-
className: ["navi_editable_wrapper", ...(wrapperProps?.className || "").split(" ")].join(" "),
|
|
17496
|
-
children: input
|
|
17497
|
-
})]
|
|
17498
|
-
});
|
|
17499
|
-
});
|
|
17346
|
+
/**
|
|
17347
|
+
*
|
|
17348
|
+
* Here we want the same behaviour as web standards:
|
|
17349
|
+
*
|
|
17350
|
+
* 1. When submitting the form URL does not change
|
|
17351
|
+
* 2. When form submission id done user is redirected (by default the current one)
|
|
17352
|
+
* (we can configure this using target)
|
|
17353
|
+
* So for example user might be reidrect to a page with the resource he just created
|
|
17354
|
+
* I could create an example where we would put a link on the page to let user see what he created
|
|
17355
|
+
* but by default user stays on the form allowing to create multiple resources at once
|
|
17356
|
+
* And an other where he is redirected to the resource he created
|
|
17357
|
+
* 3. If form submission fails ideally we should display this somewhere on the UI
|
|
17358
|
+
* right now it's just logged to the console I need to see how we can achieve this
|
|
17359
|
+
*/
|
|
17500
17360
|
|
|
17501
|
-
|
|
17502
|
-
|
|
17503
|
-
|
|
17504
|
-
display: flex;
|
|
17505
|
-
flex-direction: column;
|
|
17506
|
-
}
|
|
17507
|
-
}
|
|
17508
|
-
`;
|
|
17509
|
-
const CheckboxList = forwardRef((props, ref) => {
|
|
17510
|
-
const uiStateController = useUIGroupStateController(props, "checkbox_list", {
|
|
17511
|
-
childComponentType: "checkbox",
|
|
17361
|
+
const Form = props => {
|
|
17362
|
+
const uiStateController = useUIGroupStateController(props, "form", {
|
|
17363
|
+
childComponentType: "*",
|
|
17512
17364
|
aggregateChildStates: childUIStateControllers => {
|
|
17513
|
-
const
|
|
17365
|
+
const formValues = {};
|
|
17514
17366
|
for (const childUIStateController of childUIStateControllers) {
|
|
17515
|
-
|
|
17516
|
-
|
|
17367
|
+
const {
|
|
17368
|
+
name,
|
|
17369
|
+
uiState
|
|
17370
|
+
} = childUIStateController;
|
|
17371
|
+
if (!name) {
|
|
17372
|
+
console.warn("A form child component is missing a name property, its state won't be included in the form state", childUIStateController);
|
|
17373
|
+
continue;
|
|
17517
17374
|
}
|
|
17375
|
+
formValues[name] = uiState;
|
|
17518
17376
|
}
|
|
17519
|
-
return
|
|
17377
|
+
return formValues;
|
|
17520
17378
|
}
|
|
17521
17379
|
});
|
|
17522
17380
|
const uiState = useUIState(uiStateController);
|
|
17523
|
-
const
|
|
17381
|
+
const form = renderActionableComponent(props, {
|
|
17382
|
+
Basic: FormBasic,
|
|
17383
|
+
WithAction: FormWithAction
|
|
17384
|
+
});
|
|
17524
17385
|
return jsx(UIStateControllerContext.Provider, {
|
|
17525
17386
|
value: uiStateController,
|
|
17526
17387
|
children: jsx(UIStateContext.Provider, {
|
|
17527
17388
|
value: uiState,
|
|
17528
|
-
children:
|
|
17389
|
+
children: form
|
|
17529
17390
|
})
|
|
17530
17391
|
});
|
|
17531
|
-
}
|
|
17532
|
-
const
|
|
17533
|
-
const CheckboxListBasic = forwardRef((props, ref) => {
|
|
17534
|
-
const contextReadOnly = useContext(ReadOnlyContext);
|
|
17535
|
-
const contextDisabled = useContext(DisabledContext);
|
|
17536
|
-
const contextLoading = useContext(LoadingContext);
|
|
17392
|
+
};
|
|
17393
|
+
const FormBasic = props => {
|
|
17537
17394
|
const uiStateController = useContext(UIStateControllerContext);
|
|
17538
17395
|
const {
|
|
17539
|
-
name,
|
|
17540
17396
|
readOnly,
|
|
17541
|
-
disabled,
|
|
17542
|
-
required,
|
|
17543
17397
|
loading,
|
|
17544
17398
|
children,
|
|
17545
17399
|
...rest
|
|
17546
17400
|
} = props;
|
|
17547
|
-
const
|
|
17548
|
-
|
|
17549
|
-
|
|
17550
|
-
|
|
17551
|
-
|
|
17552
|
-
|
|
17401
|
+
const defaultRef = useRef();
|
|
17402
|
+
const ref = props.ref || defaultRef;
|
|
17403
|
+
|
|
17404
|
+
// instantiation validation to:
|
|
17405
|
+
// - receive "requestsubmit" custom event ensure submit is prevented
|
|
17406
|
+
// (and also execute action without validation if form.submit() is ever called)
|
|
17407
|
+
useConstraints(ref, []);
|
|
17408
|
+
const innerReadOnly = readOnly || loading;
|
|
17409
|
+
const formContextValue = useMemo(() => {
|
|
17410
|
+
return {
|
|
17411
|
+
loading
|
|
17412
|
+
};
|
|
17413
|
+
}, [loading]);
|
|
17414
|
+
return jsx(Box, {
|
|
17553
17415
|
...rest,
|
|
17554
|
-
|
|
17555
|
-
|
|
17556
|
-
|
|
17557
|
-
|
|
17558
|
-
|
|
17559
|
-
|
|
17560
|
-
onresetuistate: e => {
|
|
17416
|
+
as: "form",
|
|
17417
|
+
ref: ref,
|
|
17418
|
+
onReset: e => {
|
|
17419
|
+
// browser would empty all fields to their default values (likely empty/unchecked)
|
|
17420
|
+
// we want to reset to the last known external state instead
|
|
17421
|
+
e.preventDefault();
|
|
17561
17422
|
uiStateController.resetUIState(e);
|
|
17562
17423
|
},
|
|
17563
17424
|
children: jsx(ParentUIStateControllerContext.Provider, {
|
|
17564
17425
|
value: uiStateController,
|
|
17565
|
-
children: jsx(
|
|
17566
|
-
value:
|
|
17567
|
-
children: jsx(
|
|
17568
|
-
value:
|
|
17569
|
-
children: jsx(
|
|
17570
|
-
value:
|
|
17571
|
-
children:
|
|
17572
|
-
value: required,
|
|
17573
|
-
children: jsx(LoadingContext.Provider, {
|
|
17574
|
-
value: innerLoading,
|
|
17575
|
-
children: children
|
|
17576
|
-
})
|
|
17577
|
-
})
|
|
17426
|
+
children: jsx(ReadOnlyContext.Provider, {
|
|
17427
|
+
value: innerReadOnly,
|
|
17428
|
+
children: jsx(LoadingContext.Provider, {
|
|
17429
|
+
value: loading,
|
|
17430
|
+
children: jsx(FormContext.Provider, {
|
|
17431
|
+
value: formContextValue,
|
|
17432
|
+
children: children
|
|
17578
17433
|
})
|
|
17579
17434
|
})
|
|
17580
17435
|
})
|
|
17581
17436
|
})
|
|
17582
17437
|
});
|
|
17583
|
-
}
|
|
17584
|
-
|
|
17438
|
+
};
|
|
17439
|
+
const FormWithAction = props => {
|
|
17585
17440
|
const uiStateController = useContext(UIStateControllerContext);
|
|
17586
17441
|
const uiState = useContext(UIStateContext);
|
|
17587
17442
|
const {
|
|
17588
17443
|
action,
|
|
17589
|
-
|
|
17590
|
-
|
|
17444
|
+
method,
|
|
17445
|
+
actionErrorEffect = "show_validation_message",
|
|
17446
|
+
// "show_validation_message" or "throw"
|
|
17447
|
+
errorMapping,
|
|
17591
17448
|
onActionPrevented,
|
|
17592
17449
|
onActionStart,
|
|
17593
17450
|
onActionAbort,
|
|
@@ -17597,265 +17454,18 @@ forwardRef((props, ref) => {
|
|
|
17597
17454
|
children,
|
|
17598
17455
|
...rest
|
|
17599
17456
|
} = props;
|
|
17600
|
-
const
|
|
17601
|
-
|
|
17602
|
-
const [
|
|
17603
|
-
const {
|
|
17604
|
-
|
|
17605
|
-
|
|
17606
|
-
const executeAction = useExecuteAction(innerRef, {
|
|
17607
|
-
errorEffect: actionErrorEffect
|
|
17457
|
+
const defaultRef = useRef();
|
|
17458
|
+
const ref = props.ref || defaultRef;
|
|
17459
|
+
const [actionBoundToUIState] = useActionBoundToOneParam(action, uiState);
|
|
17460
|
+
const executeAction = useExecuteAction(ref, {
|
|
17461
|
+
errorEffect: actionErrorEffect,
|
|
17462
|
+
errorMapping
|
|
17608
17463
|
});
|
|
17609
|
-
const
|
|
17610
|
-
|
|
17611
|
-
|
|
17612
|
-
|
|
17613
|
-
|
|
17614
|
-
},
|
|
17615
|
-
onPrevented: onActionPrevented,
|
|
17616
|
-
onAction: actionEvent => {
|
|
17617
|
-
setActionRequester(actionEvent.detail.requester);
|
|
17618
|
-
executeAction(actionEvent);
|
|
17619
|
-
},
|
|
17620
|
-
onStart: onActionStart,
|
|
17621
|
-
onAbort: e => {
|
|
17622
|
-
uiStateController.resetUIState(e);
|
|
17623
|
-
onActionAbort?.(e);
|
|
17624
|
-
},
|
|
17625
|
-
onError: e => {
|
|
17626
|
-
uiStateController.resetUIState(e);
|
|
17627
|
-
onActionError?.(e);
|
|
17628
|
-
},
|
|
17629
|
-
onEnd: e => {
|
|
17630
|
-
onActionEnd?.(e);
|
|
17631
|
-
}
|
|
17632
|
-
});
|
|
17633
|
-
return jsx(CheckboxListBasic, {
|
|
17634
|
-
"data-action": boundAction.name,
|
|
17635
|
-
...rest,
|
|
17636
|
-
ref: innerRef,
|
|
17637
|
-
onChange: event => {
|
|
17638
|
-
const checkboxList = innerRef.current;
|
|
17639
|
-
const checkbox = event.target;
|
|
17640
|
-
requestAction(checkboxList, boundAction, {
|
|
17641
|
-
event,
|
|
17642
|
-
requester: checkbox
|
|
17643
|
-
});
|
|
17644
|
-
},
|
|
17645
|
-
loading: loading || actionLoading,
|
|
17646
|
-
children: jsx(LoadingElementContext.Provider, {
|
|
17647
|
-
value: actionRequester,
|
|
17648
|
-
children: children
|
|
17649
|
-
})
|
|
17650
|
-
});
|
|
17651
|
-
});
|
|
17652
|
-
|
|
17653
|
-
const collectFormElementValues = (element) => {
|
|
17654
|
-
let formElements;
|
|
17655
|
-
if (element.tagName === "FORM") {
|
|
17656
|
-
formElements = element.elements;
|
|
17657
|
-
} else {
|
|
17658
|
-
// fieldset or anything else
|
|
17659
|
-
formElements = element.querySelectorAll(
|
|
17660
|
-
"input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button[name]:not([disabled])",
|
|
17661
|
-
);
|
|
17662
|
-
}
|
|
17663
|
-
|
|
17664
|
-
const values = {};
|
|
17665
|
-
const checkboxArrayNameSet = new Set();
|
|
17666
|
-
for (const formElement of formElements) {
|
|
17667
|
-
if (formElement.type === "checkbox" && formElement.name) {
|
|
17668
|
-
const name = formElement.name;
|
|
17669
|
-
const endsWithBrackets = name.endsWith("[]");
|
|
17670
|
-
if (endsWithBrackets) {
|
|
17671
|
-
checkboxArrayNameSet.add(name);
|
|
17672
|
-
values[name] = [];
|
|
17673
|
-
continue;
|
|
17674
|
-
}
|
|
17675
|
-
const closestDataCheckboxList = formElement.closest(
|
|
17676
|
-
"[data-checkbox-list]",
|
|
17677
|
-
);
|
|
17678
|
-
if (closestDataCheckboxList) {
|
|
17679
|
-
checkboxArrayNameSet.add(name);
|
|
17680
|
-
values[name] = [];
|
|
17681
|
-
}
|
|
17682
|
-
}
|
|
17683
|
-
}
|
|
17684
|
-
|
|
17685
|
-
for (const formElement of formElements) {
|
|
17686
|
-
const name = formElement.name;
|
|
17687
|
-
if (!name) {
|
|
17688
|
-
continue;
|
|
17689
|
-
}
|
|
17690
|
-
const value = getFormElementValue(formElement);
|
|
17691
|
-
if (value === undefined) {
|
|
17692
|
-
continue; // Skip unchecked checkboxes/radios
|
|
17693
|
-
}
|
|
17694
|
-
if (formElement.type === "checkbox" && checkboxArrayNameSet.has(name)) {
|
|
17695
|
-
values[name].push(value);
|
|
17696
|
-
} else {
|
|
17697
|
-
values[name] = value;
|
|
17698
|
-
}
|
|
17699
|
-
}
|
|
17700
|
-
return values;
|
|
17701
|
-
};
|
|
17702
|
-
|
|
17703
|
-
const getFormElementValue = (formElement) => {
|
|
17704
|
-
const { type, tagName } = formElement;
|
|
17705
|
-
|
|
17706
|
-
if (tagName === "SELECT") {
|
|
17707
|
-
if (formElement.multiple) {
|
|
17708
|
-
return Array.from(formElement.selectedOptions, (option) =>
|
|
17709
|
-
getValue(option),
|
|
17710
|
-
);
|
|
17711
|
-
}
|
|
17712
|
-
return formElement.value;
|
|
17713
|
-
}
|
|
17714
|
-
|
|
17715
|
-
if (type === "checkbox" || type === "radio") {
|
|
17716
|
-
return formElement.checked ? getValue(formElement) : undefined;
|
|
17717
|
-
}
|
|
17718
|
-
|
|
17719
|
-
if (type === "file") {
|
|
17720
|
-
return formElement.files; // Return FileList for special handling
|
|
17721
|
-
}
|
|
17722
|
-
|
|
17723
|
-
return getValue(formElement);
|
|
17724
|
-
};
|
|
17725
|
-
|
|
17726
|
-
const getValue = (formElement) => {
|
|
17727
|
-
const hasDataValueAttribute = formElement.hasAttribute("data-value");
|
|
17728
|
-
if (hasDataValueAttribute) {
|
|
17729
|
-
// happens for "datetime-local" inputs to keep the timezone
|
|
17730
|
-
// consistent when sending to the server
|
|
17731
|
-
return formElement.getAttribute("data-value");
|
|
17732
|
-
}
|
|
17733
|
-
return formElement.value;
|
|
17734
|
-
};
|
|
17735
|
-
|
|
17736
|
-
/**
|
|
17737
|
-
*
|
|
17738
|
-
* Here we want the same behaviour as web standards:
|
|
17739
|
-
*
|
|
17740
|
-
* 1. When submitting the form URL does not change
|
|
17741
|
-
* 2. When form submission id done user is redirected (by default the current one)
|
|
17742
|
-
* (we can configure this using target)
|
|
17743
|
-
* So for example user might be reidrect to a page with the resource he just created
|
|
17744
|
-
* I could create an example where we would put a link on the page to let user see what he created
|
|
17745
|
-
* but by default user stays on the form allowing to create multiple resources at once
|
|
17746
|
-
* And an other where he is redirected to the resource he created
|
|
17747
|
-
* 3. If form submission fails ideally we should display this somewhere on the UI
|
|
17748
|
-
* right now it's just logged to the console I need to see how we can achieve this
|
|
17749
|
-
*/
|
|
17750
|
-
|
|
17751
|
-
const Form = props => {
|
|
17752
|
-
const uiStateController = useUIGroupStateController(props, "form", {
|
|
17753
|
-
childComponentType: "*",
|
|
17754
|
-
aggregateChildStates: childUIStateControllers => {
|
|
17755
|
-
const formValues = {};
|
|
17756
|
-
for (const childUIStateController of childUIStateControllers) {
|
|
17757
|
-
const {
|
|
17758
|
-
name,
|
|
17759
|
-
uiState
|
|
17760
|
-
} = childUIStateController;
|
|
17761
|
-
if (!name) {
|
|
17762
|
-
console.warn("A form child component is missing a name property, its state won't be included in the form state", childUIStateController);
|
|
17763
|
-
continue;
|
|
17764
|
-
}
|
|
17765
|
-
formValues[name] = uiState;
|
|
17766
|
-
}
|
|
17767
|
-
return formValues;
|
|
17768
|
-
}
|
|
17769
|
-
});
|
|
17770
|
-
const uiState = useUIState(uiStateController);
|
|
17771
|
-
const form = renderActionableComponent(props, {
|
|
17772
|
-
Basic: FormBasic,
|
|
17773
|
-
WithAction: FormWithAction
|
|
17774
|
-
});
|
|
17775
|
-
return jsx(UIStateControllerContext.Provider, {
|
|
17776
|
-
value: uiStateController,
|
|
17777
|
-
children: jsx(UIStateContext.Provider, {
|
|
17778
|
-
value: uiState,
|
|
17779
|
-
children: form
|
|
17780
|
-
})
|
|
17781
|
-
});
|
|
17782
|
-
};
|
|
17783
|
-
const FormBasic = props => {
|
|
17784
|
-
const uiStateController = useContext(UIStateControllerContext);
|
|
17785
|
-
const {
|
|
17786
|
-
readOnly,
|
|
17787
|
-
loading,
|
|
17788
|
-
children,
|
|
17789
|
-
...rest
|
|
17790
|
-
} = props;
|
|
17791
|
-
const defaultRef = useRef();
|
|
17792
|
-
const ref = props.ref || defaultRef;
|
|
17793
|
-
|
|
17794
|
-
// instantiation validation to:
|
|
17795
|
-
// - receive "requestsubmit" custom event ensure submit is prevented
|
|
17796
|
-
// (and also execute action without validation if form.submit() is ever called)
|
|
17797
|
-
useConstraints(ref, []);
|
|
17798
|
-
const innerReadOnly = readOnly || loading;
|
|
17799
|
-
const formContextValue = useMemo(() => {
|
|
17800
|
-
return {
|
|
17801
|
-
loading
|
|
17802
|
-
};
|
|
17803
|
-
}, [loading]);
|
|
17804
|
-
return jsx(Box, {
|
|
17805
|
-
...rest,
|
|
17806
|
-
as: "form",
|
|
17807
|
-
ref: ref,
|
|
17808
|
-
onReset: e => {
|
|
17809
|
-
// browser would empty all fields to their default values (likely empty/unchecked)
|
|
17810
|
-
// we want to reset to the last known external state instead
|
|
17811
|
-
e.preventDefault();
|
|
17812
|
-
uiStateController.resetUIState(e);
|
|
17813
|
-
},
|
|
17814
|
-
children: jsx(ParentUIStateControllerContext.Provider, {
|
|
17815
|
-
value: uiStateController,
|
|
17816
|
-
children: jsx(ReadOnlyContext.Provider, {
|
|
17817
|
-
value: innerReadOnly,
|
|
17818
|
-
children: jsx(LoadingContext.Provider, {
|
|
17819
|
-
value: loading,
|
|
17820
|
-
children: jsx(FormContext.Provider, {
|
|
17821
|
-
value: formContextValue,
|
|
17822
|
-
children: children
|
|
17823
|
-
})
|
|
17824
|
-
})
|
|
17825
|
-
})
|
|
17826
|
-
})
|
|
17827
|
-
});
|
|
17828
|
-
};
|
|
17829
|
-
const FormWithAction = props => {
|
|
17830
|
-
const uiStateController = useContext(UIStateControllerContext);
|
|
17831
|
-
const uiState = useContext(UIStateContext);
|
|
17832
|
-
const {
|
|
17833
|
-
action,
|
|
17834
|
-
method,
|
|
17835
|
-
actionErrorEffect = "show_validation_message",
|
|
17836
|
-
// "show_validation_message" or "throw"
|
|
17837
|
-
errorMapping,
|
|
17838
|
-
onActionPrevented,
|
|
17839
|
-
onActionStart,
|
|
17840
|
-
onActionAbort,
|
|
17841
|
-
onActionError,
|
|
17842
|
-
onActionEnd,
|
|
17843
|
-
loading,
|
|
17844
|
-
children,
|
|
17845
|
-
...rest
|
|
17846
|
-
} = props;
|
|
17847
|
-
const defaultRef = useRef();
|
|
17848
|
-
const ref = props.ref || defaultRef;
|
|
17849
|
-
const [actionBoundToUIState] = useActionBoundToOneParam(action, uiState);
|
|
17850
|
-
const executeAction = useExecuteAction(ref, {
|
|
17851
|
-
errorEffect: actionErrorEffect,
|
|
17852
|
-
errorMapping
|
|
17853
|
-
});
|
|
17854
|
-
const {
|
|
17855
|
-
actionPending,
|
|
17856
|
-
actionRequester: formActionRequester
|
|
17857
|
-
} = useRequestedActionStatus(ref);
|
|
17858
|
-
useActionEvents(ref, {
|
|
17464
|
+
const {
|
|
17465
|
+
actionPending,
|
|
17466
|
+
actionRequester: formActionRequester
|
|
17467
|
+
} = useRequestedActionStatus(ref);
|
|
17468
|
+
useActionEvents(ref, {
|
|
17859
17469
|
onPrevented: onActionPrevented,
|
|
17860
17470
|
onRequested: e => {
|
|
17861
17471
|
forwardActionRequested(e, actionBoundToUIState);
|
|
@@ -18104,213 +17714,759 @@ const useRefArray = (items, keyFromItem) => {
|
|
|
18104
17714
|
};
|
|
18105
17715
|
|
|
18106
17716
|
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
18107
|
-
.navi_select[data-readonly] {
|
|
18108
|
-
pointer-events: none;
|
|
17717
|
+
.navi_select[data-readonly] {
|
|
17718
|
+
pointer-events: none;
|
|
17719
|
+
}
|
|
17720
|
+
`;
|
|
17721
|
+
const Select = forwardRef((props, ref) => {
|
|
17722
|
+
const select = renderActionableComponent(props, ref);
|
|
17723
|
+
return select;
|
|
17724
|
+
});
|
|
17725
|
+
const SelectControlled = forwardRef((props, ref) => {
|
|
17726
|
+
const {
|
|
17727
|
+
name,
|
|
17728
|
+
value,
|
|
17729
|
+
loading,
|
|
17730
|
+
disabled,
|
|
17731
|
+
readOnly,
|
|
17732
|
+
children,
|
|
17733
|
+
...rest
|
|
17734
|
+
} = props;
|
|
17735
|
+
const innerRef = useRef();
|
|
17736
|
+
useImperativeHandle(ref, () => innerRef.current);
|
|
17737
|
+
const selectElement = jsx("select", {
|
|
17738
|
+
className: "navi_select",
|
|
17739
|
+
ref: innerRef,
|
|
17740
|
+
"data-readonly": readOnly && !disabled ? "" : undefined,
|
|
17741
|
+
onKeyDown: e => {
|
|
17742
|
+
if (readOnly) {
|
|
17743
|
+
e.preventDefault();
|
|
17744
|
+
}
|
|
17745
|
+
},
|
|
17746
|
+
...rest,
|
|
17747
|
+
children: children.map(child => {
|
|
17748
|
+
const {
|
|
17749
|
+
label,
|
|
17750
|
+
readOnly: childReadOnly,
|
|
17751
|
+
disabled: childDisabled,
|
|
17752
|
+
loading: childLoading,
|
|
17753
|
+
value: childValue,
|
|
17754
|
+
...childRest
|
|
17755
|
+
} = child;
|
|
17756
|
+
return jsx("option", {
|
|
17757
|
+
name: name,
|
|
17758
|
+
value: childValue,
|
|
17759
|
+
selected: childValue === value,
|
|
17760
|
+
readOnly: readOnly || childReadOnly,
|
|
17761
|
+
disabled: disabled || childDisabled,
|
|
17762
|
+
loading: loading || childLoading,
|
|
17763
|
+
...childRest,
|
|
17764
|
+
children: label
|
|
17765
|
+
}, childValue);
|
|
17766
|
+
})
|
|
17767
|
+
});
|
|
17768
|
+
return jsx(LoaderBackground, {
|
|
17769
|
+
loading: loading,
|
|
17770
|
+
color: "light-dark(#355fcc, #3b82f6)",
|
|
17771
|
+
inset: -1,
|
|
17772
|
+
children: selectElement
|
|
17773
|
+
});
|
|
17774
|
+
});
|
|
17775
|
+
forwardRef((props, ref) => {
|
|
17776
|
+
const {
|
|
17777
|
+
value: initialValue,
|
|
17778
|
+
id,
|
|
17779
|
+
children,
|
|
17780
|
+
...rest
|
|
17781
|
+
} = props;
|
|
17782
|
+
const innerRef = useRef();
|
|
17783
|
+
useImperativeHandle(ref, () => innerRef.current);
|
|
17784
|
+
const [navState, setNavState] = useNavState(id);
|
|
17785
|
+
const valueAtStart = navState === undefined ? initialValue : navState;
|
|
17786
|
+
const [value, setValue] = useState(valueAtStart);
|
|
17787
|
+
useEffect(() => {
|
|
17788
|
+
setNavState(value);
|
|
17789
|
+
}, [value]);
|
|
17790
|
+
return jsx(SelectControlled, {
|
|
17791
|
+
ref: innerRef,
|
|
17792
|
+
value: value,
|
|
17793
|
+
onChange: event => {
|
|
17794
|
+
const select = event.target;
|
|
17795
|
+
const selectedValue = select.value;
|
|
17796
|
+
setValue(selectedValue);
|
|
17797
|
+
},
|
|
17798
|
+
...rest,
|
|
17799
|
+
children: children
|
|
17800
|
+
});
|
|
17801
|
+
});
|
|
17802
|
+
forwardRef((props, ref) => {
|
|
17803
|
+
const {
|
|
17804
|
+
id,
|
|
17805
|
+
name,
|
|
17806
|
+
value: externalValue,
|
|
17807
|
+
valueSignal,
|
|
17808
|
+
action,
|
|
17809
|
+
children,
|
|
17810
|
+
onCancel,
|
|
17811
|
+
onActionPrevented,
|
|
17812
|
+
onActionStart,
|
|
17813
|
+
onActionAbort,
|
|
17814
|
+
onActionError,
|
|
17815
|
+
onActionEnd,
|
|
17816
|
+
actionErrorEffect,
|
|
17817
|
+
...rest
|
|
17818
|
+
} = props;
|
|
17819
|
+
const innerRef = useRef();
|
|
17820
|
+
useImperativeHandle(ref, () => innerRef.current);
|
|
17821
|
+
const [navState, setNavState, resetNavState] = useNavState(id);
|
|
17822
|
+
const [boundAction, value, setValue, initialValue] = useActionBoundToOneParam(action, name);
|
|
17823
|
+
const {
|
|
17824
|
+
loading: actionLoading
|
|
17825
|
+
} = useActionStatus(boundAction);
|
|
17826
|
+
const executeAction = useExecuteAction(innerRef, {
|
|
17827
|
+
errorEffect: actionErrorEffect
|
|
17828
|
+
});
|
|
17829
|
+
useEffect(() => {
|
|
17830
|
+
setNavState(value);
|
|
17831
|
+
}, [value]);
|
|
17832
|
+
const actionRequesterRef = useRef(null);
|
|
17833
|
+
useActionEvents(innerRef, {
|
|
17834
|
+
onCancel: (e, reason) => {
|
|
17835
|
+
resetNavState();
|
|
17836
|
+
setValue(initialValue);
|
|
17837
|
+
onCancel?.(e, reason);
|
|
17838
|
+
},
|
|
17839
|
+
onPrevented: onActionPrevented,
|
|
17840
|
+
onAction: actionEvent => {
|
|
17841
|
+
actionRequesterRef.current = actionEvent.detail.requester;
|
|
17842
|
+
executeAction(actionEvent);
|
|
17843
|
+
},
|
|
17844
|
+
onStart: onActionStart,
|
|
17845
|
+
onAbort: e => {
|
|
17846
|
+
setValue(initialValue);
|
|
17847
|
+
onActionAbort?.(e);
|
|
17848
|
+
},
|
|
17849
|
+
onError: error => {
|
|
17850
|
+
setValue(initialValue);
|
|
17851
|
+
onActionError?.(error);
|
|
17852
|
+
},
|
|
17853
|
+
onEnd: () => {
|
|
17854
|
+
resetNavState();
|
|
17855
|
+
onActionEnd?.();
|
|
17856
|
+
}
|
|
17857
|
+
});
|
|
17858
|
+
const childRefArray = useRefArray(children, child => child.value);
|
|
17859
|
+
return jsx(SelectControlled, {
|
|
17860
|
+
ref: innerRef,
|
|
17861
|
+
name: name,
|
|
17862
|
+
value: value,
|
|
17863
|
+
"data-action": boundAction,
|
|
17864
|
+
onChange: event => {
|
|
17865
|
+
const select = event.target;
|
|
17866
|
+
const selectedValue = select.value;
|
|
17867
|
+
setValue(selectedValue);
|
|
17868
|
+
const radioListContainer = innerRef.current;
|
|
17869
|
+
const optionSelected = select.querySelector(`option[value="${selectedValue}"]`);
|
|
17870
|
+
requestAction(radioListContainer, boundAction, {
|
|
17871
|
+
event,
|
|
17872
|
+
requester: optionSelected
|
|
17873
|
+
});
|
|
17874
|
+
},
|
|
17875
|
+
...rest,
|
|
17876
|
+
children: children.map((child, i) => {
|
|
17877
|
+
const childRef = childRefArray[i];
|
|
17878
|
+
return {
|
|
17879
|
+
...child,
|
|
17880
|
+
ref: childRef,
|
|
17881
|
+
loading: child.loading || actionLoading && actionRequesterRef.current === childRef.current,
|
|
17882
|
+
readOnly: child.readOnly || actionLoading
|
|
17883
|
+
};
|
|
17884
|
+
})
|
|
17885
|
+
});
|
|
17886
|
+
});
|
|
17887
|
+
forwardRef((props, ref) => {
|
|
17888
|
+
const {
|
|
17889
|
+
id,
|
|
17890
|
+
name,
|
|
17891
|
+
value: externalValue,
|
|
17892
|
+
children,
|
|
17893
|
+
...rest
|
|
17894
|
+
} = props;
|
|
17895
|
+
const innerRef = useRef();
|
|
17896
|
+
useImperativeHandle(ref, () => innerRef.current);
|
|
17897
|
+
const [navState, setNavState] = useNavState(id);
|
|
17898
|
+
const [value, setValue, initialValue] = [name, externalValue, navState];
|
|
17899
|
+
useEffect(() => {
|
|
17900
|
+
setNavState(value);
|
|
17901
|
+
}, [value]);
|
|
17902
|
+
useFormEvents(innerRef, {
|
|
17903
|
+
onFormReset: () => {
|
|
17904
|
+
setValue(undefined);
|
|
17905
|
+
},
|
|
17906
|
+
onFormActionAbort: () => {
|
|
17907
|
+
setValue(initialValue);
|
|
17908
|
+
},
|
|
17909
|
+
onFormActionError: () => {
|
|
17910
|
+
setValue(initialValue);
|
|
17911
|
+
}
|
|
17912
|
+
});
|
|
17913
|
+
return jsx(SelectControlled, {
|
|
17914
|
+
ref: innerRef,
|
|
17915
|
+
name: name,
|
|
17916
|
+
value: value,
|
|
17917
|
+
onChange: event => {
|
|
17918
|
+
const select = event.target;
|
|
17919
|
+
const selectedValue = select.checked;
|
|
17920
|
+
setValue(selectedValue);
|
|
17921
|
+
},
|
|
17922
|
+
...rest,
|
|
17923
|
+
children: children
|
|
17924
|
+
});
|
|
17925
|
+
});
|
|
17926
|
+
|
|
17927
|
+
const createUniqueValueConstraint = (
|
|
17928
|
+
// the set might be incomplete (the front usually don't have the full copy of all the items from the backend)
|
|
17929
|
+
// but this is already nice to help user with what we know
|
|
17930
|
+
// it's also possible that front is unsync with backend, preventing user to choose a value
|
|
17931
|
+
// that is actually free.
|
|
17932
|
+
// But this is unlikely to happen and user could reload the page to be able to choose that name
|
|
17933
|
+
// that suddenly became available
|
|
17934
|
+
existingValueSet,
|
|
17935
|
+
message = `"{value}" already exists. Please choose another value.`,
|
|
17936
|
+
) => {
|
|
17937
|
+
return {
|
|
17938
|
+
name: "unique_value",
|
|
17939
|
+
check: (input) => {
|
|
17940
|
+
const inputValue = input.value;
|
|
17941
|
+
const hasConflict = existingValueSet.has(inputValue);
|
|
17942
|
+
// console.log({
|
|
17943
|
+
// inputValue,
|
|
17944
|
+
// names: Array.from(otherNameSet.values()),
|
|
17945
|
+
// hasConflict,
|
|
17946
|
+
// });
|
|
17947
|
+
if (hasConflict) {
|
|
17948
|
+
return message.replace("{value}", inputValue);
|
|
17949
|
+
}
|
|
17950
|
+
return "";
|
|
17951
|
+
},
|
|
17952
|
+
};
|
|
17953
|
+
};
|
|
17954
|
+
|
|
17955
|
+
const SINGLE_SPACE_CONSTRAINT = {
|
|
17956
|
+
name: "single_space",
|
|
17957
|
+
check: (input) => {
|
|
17958
|
+
const inputValue = input.value;
|
|
17959
|
+
const hasLeadingSpace = inputValue.startsWith(" ");
|
|
17960
|
+
const hasTrailingSpace = inputValue.endsWith(" ");
|
|
17961
|
+
const hasDoubleSpace = inputValue.includes(" ");
|
|
17962
|
+
if (hasLeadingSpace || hasDoubleSpace || hasTrailingSpace) {
|
|
17963
|
+
return "Spaces at the beginning, end, or consecutive spaces are not allowed";
|
|
17964
|
+
}
|
|
17965
|
+
return "";
|
|
17966
|
+
},
|
|
17967
|
+
};
|
|
17968
|
+
|
|
17969
|
+
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
17970
|
+
.action_error {
|
|
17971
|
+
padding: 20px;
|
|
17972
|
+
background: #fdd;
|
|
17973
|
+
border: 1px solid red;
|
|
17974
|
+
margin-top: 0;
|
|
17975
|
+
margin-bottom: 20px;
|
|
17976
|
+
}
|
|
17977
|
+
`;
|
|
17978
|
+
const renderIdleDefault = () => null;
|
|
17979
|
+
const renderLoadingDefault = () => null;
|
|
17980
|
+
const renderAbortedDefault = () => null;
|
|
17981
|
+
const renderErrorDefault = error => {
|
|
17982
|
+
let routeErrorText = error && error.message ? error.message : error;
|
|
17983
|
+
return jsxs("p", {
|
|
17984
|
+
className: "action_error",
|
|
17985
|
+
children: ["An error occured: ", routeErrorText]
|
|
17986
|
+
});
|
|
17987
|
+
};
|
|
17988
|
+
const renderCompletedDefault = () => null;
|
|
17989
|
+
const ActionRenderer = ({
|
|
17990
|
+
action,
|
|
17991
|
+
children,
|
|
17992
|
+
disabled
|
|
17993
|
+
}) => {
|
|
17994
|
+
const {
|
|
17995
|
+
idle: renderIdle = renderIdleDefault,
|
|
17996
|
+
loading: renderLoading = renderLoadingDefault,
|
|
17997
|
+
aborted: renderAborted = renderAbortedDefault,
|
|
17998
|
+
error: renderError = renderErrorDefault,
|
|
17999
|
+
completed: renderCompleted,
|
|
18000
|
+
always: renderAlways
|
|
18001
|
+
} = typeof children === "function" ? {
|
|
18002
|
+
completed: children
|
|
18003
|
+
} : children || {};
|
|
18004
|
+
if (disabled) {
|
|
18005
|
+
return null;
|
|
18006
|
+
}
|
|
18007
|
+
if (action === undefined) {
|
|
18008
|
+
throw new Error("ActionRenderer requires an action to render, but none was provided.");
|
|
18009
|
+
}
|
|
18010
|
+
const {
|
|
18011
|
+
idle,
|
|
18012
|
+
loading,
|
|
18013
|
+
aborted,
|
|
18014
|
+
error,
|
|
18015
|
+
data
|
|
18016
|
+
} = useActionStatus(action);
|
|
18017
|
+
const UIRenderedPromise = useUIRenderedPromise(action);
|
|
18018
|
+
const [errorBoundary, resetErrorBoundary] = useErrorBoundary();
|
|
18019
|
+
|
|
18020
|
+
// Mark this action as bound to UI components (has renderers)
|
|
18021
|
+
// This tells the action system that errors should be caught and stored
|
|
18022
|
+
// in the action's error state rather than bubbling up
|
|
18023
|
+
useLayoutEffect(() => {
|
|
18024
|
+
if (action) {
|
|
18025
|
+
const {
|
|
18026
|
+
ui
|
|
18027
|
+
} = getActionPrivateProperties(action);
|
|
18028
|
+
ui.hasRenderers = true;
|
|
18029
|
+
}
|
|
18030
|
+
}, [action]);
|
|
18031
|
+
useLayoutEffect(() => {
|
|
18032
|
+
resetErrorBoundary();
|
|
18033
|
+
}, [action, loading, idle, resetErrorBoundary]);
|
|
18034
|
+
useLayoutEffect(() => {
|
|
18035
|
+
UIRenderedPromise.resolve();
|
|
18036
|
+
return () => {
|
|
18037
|
+
actionUIRenderedPromiseWeakMap.delete(action);
|
|
18038
|
+
};
|
|
18039
|
+
}, [action]);
|
|
18040
|
+
|
|
18041
|
+
// If renderAlways is provided, it wins and handles all rendering
|
|
18042
|
+
if (renderAlways) {
|
|
18043
|
+
return renderAlways({
|
|
18044
|
+
idle,
|
|
18045
|
+
loading,
|
|
18046
|
+
aborted,
|
|
18047
|
+
error,
|
|
18048
|
+
data
|
|
18049
|
+
});
|
|
18050
|
+
}
|
|
18051
|
+
if (idle) {
|
|
18052
|
+
return renderIdle(action);
|
|
18053
|
+
}
|
|
18054
|
+
if (errorBoundary) {
|
|
18055
|
+
return renderError(errorBoundary, "ui_error", action);
|
|
18056
|
+
}
|
|
18057
|
+
if (error) {
|
|
18058
|
+
return renderError(error, "action_error", action);
|
|
18059
|
+
}
|
|
18060
|
+
if (aborted) {
|
|
18061
|
+
return renderAborted(action);
|
|
18062
|
+
}
|
|
18063
|
+
let renderCompletedSafe;
|
|
18064
|
+
if (renderCompleted) {
|
|
18065
|
+
renderCompletedSafe = renderCompleted;
|
|
18066
|
+
} else {
|
|
18067
|
+
const {
|
|
18068
|
+
ui
|
|
18069
|
+
} = getActionPrivateProperties(action);
|
|
18070
|
+
if (ui.renderCompleted) {
|
|
18071
|
+
renderCompletedSafe = ui.renderCompleted;
|
|
18072
|
+
} else {
|
|
18073
|
+
renderCompletedSafe = renderCompletedDefault;
|
|
18074
|
+
}
|
|
18075
|
+
}
|
|
18076
|
+
if (loading) {
|
|
18077
|
+
if (action.canDisplayOldData && data !== undefined) {
|
|
18078
|
+
return renderCompletedSafe(data, action);
|
|
18079
|
+
}
|
|
18080
|
+
return renderLoading(action);
|
|
18081
|
+
}
|
|
18082
|
+
return renderCompletedSafe(data, action);
|
|
18083
|
+
};
|
|
18084
|
+
const defaultPromise = Promise.resolve();
|
|
18085
|
+
defaultPromise.resolve = () => {};
|
|
18086
|
+
const actionUIRenderedPromiseWeakMap = new WeakMap();
|
|
18087
|
+
const useUIRenderedPromise = action => {
|
|
18088
|
+
if (!action) {
|
|
18089
|
+
return defaultPromise;
|
|
18090
|
+
}
|
|
18091
|
+
const actionUIRenderedPromise = actionUIRenderedPromiseWeakMap.get(action);
|
|
18092
|
+
if (actionUIRenderedPromise) {
|
|
18093
|
+
return actionUIRenderedPromise;
|
|
18094
|
+
}
|
|
18095
|
+
let resolve;
|
|
18096
|
+
const promise = new Promise(res => {
|
|
18097
|
+
resolve = res;
|
|
18098
|
+
});
|
|
18099
|
+
promise.resolve = resolve;
|
|
18100
|
+
actionUIRenderedPromiseWeakMap.set(action, promise);
|
|
18101
|
+
return promise;
|
|
18102
|
+
};
|
|
18103
|
+
|
|
18104
|
+
const useFocusGroup = (
|
|
18105
|
+
elementRef,
|
|
18106
|
+
{ enabled = true, direction, skipTab, loop, name } = {},
|
|
18107
|
+
) => {
|
|
18108
|
+
useLayoutEffect(() => {
|
|
18109
|
+
if (!enabled) {
|
|
18110
|
+
return null;
|
|
18111
|
+
}
|
|
18112
|
+
const focusGroup = initFocusGroup(elementRef.current, {
|
|
18113
|
+
direction,
|
|
18114
|
+
skipTab,
|
|
18115
|
+
loop,
|
|
18116
|
+
name,
|
|
18117
|
+
});
|
|
18118
|
+
return focusGroup.cleanup;
|
|
18119
|
+
}, [direction, skipTab, loop, name]);
|
|
18120
|
+
};
|
|
18121
|
+
|
|
18122
|
+
installImportMetaCss(import.meta);const rightArrowPath = "M680-480L360-160l-80-80 240-240-240-240 80-80 320 320z";
|
|
18123
|
+
const downArrowPath = "M480-280L160-600l80-80 240 240 240-240 80 80-320 320z";
|
|
18124
|
+
import.meta.css = /* css */`
|
|
18125
|
+
.summary_marker {
|
|
18126
|
+
width: 1em;
|
|
18127
|
+
height: 1em;
|
|
18128
|
+
line-height: 1em;
|
|
18129
|
+
}
|
|
18130
|
+
.summary_marker_svg .arrow {
|
|
18131
|
+
animation-duration: 0.3s;
|
|
18132
|
+
animation-fill-mode: forwards;
|
|
18133
|
+
animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
18134
|
+
}
|
|
18135
|
+
.summary_marker_svg .arrow[data-animation-target="down"] {
|
|
18136
|
+
animation-name: morph-to-down;
|
|
18137
|
+
}
|
|
18138
|
+
@keyframes morph-to-down {
|
|
18139
|
+
from {
|
|
18140
|
+
d: path("${rightArrowPath}");
|
|
18141
|
+
}
|
|
18142
|
+
to {
|
|
18143
|
+
d: path("${downArrowPath}");
|
|
18144
|
+
}
|
|
18145
|
+
}
|
|
18146
|
+
.summary_marker_svg .arrow[data-animation-target="right"] {
|
|
18147
|
+
animation-name: morph-to-right;
|
|
18148
|
+
}
|
|
18149
|
+
@keyframes morph-to-right {
|
|
18150
|
+
from {
|
|
18151
|
+
d: path("${downArrowPath}");
|
|
18152
|
+
}
|
|
18153
|
+
to {
|
|
18154
|
+
d: path("${rightArrowPath}");
|
|
18155
|
+
}
|
|
18156
|
+
}
|
|
18157
|
+
|
|
18158
|
+
.summary_marker_svg .foreground_circle {
|
|
18159
|
+
stroke-dasharray: 503 1507; /* ~25% of circle perimeter */
|
|
18160
|
+
stroke-dashoffset: 0;
|
|
18161
|
+
animation: progress-around-circle 1.5s linear infinite;
|
|
18162
|
+
}
|
|
18163
|
+
@keyframes progress-around-circle {
|
|
18164
|
+
0% {
|
|
18165
|
+
stroke-dashoffset: 0;
|
|
18166
|
+
}
|
|
18167
|
+
100% {
|
|
18168
|
+
stroke-dashoffset: -2010;
|
|
18169
|
+
}
|
|
18170
|
+
}
|
|
18171
|
+
|
|
18172
|
+
/* fading and scaling */
|
|
18173
|
+
.summary_marker_svg .arrow {
|
|
18174
|
+
transition: opacity 0.3s ease-in-out;
|
|
18175
|
+
opacity: 1;
|
|
18176
|
+
}
|
|
18177
|
+
.summary_marker_svg .loading_container {
|
|
18178
|
+
transition: transform 0.3s linear;
|
|
18179
|
+
transform: scale(0.3);
|
|
18180
|
+
}
|
|
18181
|
+
.summary_marker_svg .background_circle,
|
|
18182
|
+
.summary_marker_svg .foreground_circle {
|
|
18183
|
+
transition: opacity 0.3s ease-in-out;
|
|
18184
|
+
opacity: 0;
|
|
18185
|
+
}
|
|
18186
|
+
.summary_marker_svg[data-loading] .arrow {
|
|
18187
|
+
opacity: 0;
|
|
18188
|
+
}
|
|
18189
|
+
.summary_marker_svg[data-loading] .loading_container {
|
|
18190
|
+
transform: scale(1);
|
|
18191
|
+
}
|
|
18192
|
+
.summary_marker_svg[data-loading] .background_circle {
|
|
18193
|
+
opacity: 0.2;
|
|
18194
|
+
}
|
|
18195
|
+
.summary_marker_svg[data-loading] .foreground_circle {
|
|
18196
|
+
opacity: 1;
|
|
18197
|
+
}
|
|
18198
|
+
`;
|
|
18199
|
+
const SummaryMarker = ({
|
|
18200
|
+
open,
|
|
18201
|
+
loading
|
|
18202
|
+
}) => {
|
|
18203
|
+
const showLoading = useDebounceTrue(loading, 300);
|
|
18204
|
+
const mountedRef = useRef(false);
|
|
18205
|
+
const prevOpenRef = useRef(open);
|
|
18206
|
+
useLayoutEffect(() => {
|
|
18207
|
+
mountedRef.current = true;
|
|
18208
|
+
return () => {
|
|
18209
|
+
mountedRef.current = false;
|
|
18210
|
+
};
|
|
18211
|
+
}, []);
|
|
18212
|
+
const shouldAnimate = mountedRef.current && prevOpenRef.current !== open;
|
|
18213
|
+
prevOpenRef.current = open;
|
|
18214
|
+
return jsx("span", {
|
|
18215
|
+
className: "summary_marker",
|
|
18216
|
+
children: jsxs("svg", {
|
|
18217
|
+
className: "summary_marker_svg",
|
|
18218
|
+
viewBox: "0 -960 960 960",
|
|
18219
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
18220
|
+
"data-loading": open ? showLoading || undefined : undefined,
|
|
18221
|
+
children: [jsxs("g", {
|
|
18222
|
+
className: "loading_container",
|
|
18223
|
+
"transform-origin": "480px -480px",
|
|
18224
|
+
children: [jsx("circle", {
|
|
18225
|
+
className: "background_circle",
|
|
18226
|
+
cx: "480",
|
|
18227
|
+
cy: "-480",
|
|
18228
|
+
r: "320",
|
|
18229
|
+
stroke: "currentColor",
|
|
18230
|
+
fill: "none",
|
|
18231
|
+
strokeWidth: "60",
|
|
18232
|
+
opacity: "0.2"
|
|
18233
|
+
}), jsx("circle", {
|
|
18234
|
+
className: "foreground_circle",
|
|
18235
|
+
cx: "480",
|
|
18236
|
+
cy: "-480",
|
|
18237
|
+
r: "320",
|
|
18238
|
+
stroke: "currentColor",
|
|
18239
|
+
fill: "none",
|
|
18240
|
+
strokeWidth: "60",
|
|
18241
|
+
strokeLinecap: "round",
|
|
18242
|
+
strokeDasharray: "503 1507"
|
|
18243
|
+
})]
|
|
18244
|
+
}), jsx("g", {
|
|
18245
|
+
className: "arrow_container",
|
|
18246
|
+
"transform-origin": "480px -480px",
|
|
18247
|
+
children: jsx("path", {
|
|
18248
|
+
className: "arrow",
|
|
18249
|
+
fill: "currentColor",
|
|
18250
|
+
"data-animation-target": shouldAnimate ? open ? "down" : "right" : undefined,
|
|
18251
|
+
d: open ? downArrowPath : rightArrowPath
|
|
18252
|
+
})
|
|
18253
|
+
})]
|
|
18254
|
+
})
|
|
18255
|
+
});
|
|
18256
|
+
};
|
|
18257
|
+
|
|
18258
|
+
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
18259
|
+
.navi_details {
|
|
18260
|
+
position: relative;
|
|
18261
|
+
z-index: 1;
|
|
18262
|
+
display: flex;
|
|
18263
|
+
flex-shrink: 0;
|
|
18264
|
+
flex-direction: column;
|
|
18265
|
+
}
|
|
18266
|
+
|
|
18267
|
+
.navi_details > summary {
|
|
18268
|
+
display: flex;
|
|
18269
|
+
flex-shrink: 0;
|
|
18270
|
+
flex-direction: column;
|
|
18271
|
+
cursor: pointer;
|
|
18272
|
+
user-select: none;
|
|
18273
|
+
}
|
|
18274
|
+
.summary_body {
|
|
18275
|
+
display: flex;
|
|
18276
|
+
width: 100%;
|
|
18277
|
+
flex-direction: row;
|
|
18278
|
+
align-items: center;
|
|
18279
|
+
gap: 0.2em;
|
|
18280
|
+
}
|
|
18281
|
+
.summary_label {
|
|
18282
|
+
display: flex;
|
|
18283
|
+
padding-right: 10px;
|
|
18284
|
+
flex: 1;
|
|
18285
|
+
align-items: center;
|
|
18286
|
+
gap: 0.2em;
|
|
18287
|
+
}
|
|
18288
|
+
|
|
18289
|
+
.navi_details > summary:focus {
|
|
18290
|
+
z-index: 1;
|
|
18109
18291
|
}
|
|
18110
18292
|
`;
|
|
18111
|
-
const
|
|
18112
|
-
|
|
18113
|
-
return select;
|
|
18114
|
-
});
|
|
18115
|
-
const SelectControlled = forwardRef((props, ref) => {
|
|
18116
|
-
const {
|
|
18117
|
-
name,
|
|
18118
|
-
value,
|
|
18119
|
-
loading,
|
|
18120
|
-
disabled,
|
|
18121
|
-
readOnly,
|
|
18122
|
-
children,
|
|
18123
|
-
...rest
|
|
18124
|
-
} = props;
|
|
18125
|
-
const innerRef = useRef();
|
|
18126
|
-
useImperativeHandle(ref, () => innerRef.current);
|
|
18127
|
-
const selectElement = jsx("select", {
|
|
18128
|
-
className: "navi_select",
|
|
18129
|
-
ref: innerRef,
|
|
18130
|
-
"data-readonly": readOnly && !disabled ? "" : undefined,
|
|
18131
|
-
onKeyDown: e => {
|
|
18132
|
-
if (readOnly) {
|
|
18133
|
-
e.preventDefault();
|
|
18134
|
-
}
|
|
18135
|
-
},
|
|
18136
|
-
...rest,
|
|
18137
|
-
children: children.map(child => {
|
|
18138
|
-
const {
|
|
18139
|
-
label,
|
|
18140
|
-
readOnly: childReadOnly,
|
|
18141
|
-
disabled: childDisabled,
|
|
18142
|
-
loading: childLoading,
|
|
18143
|
-
value: childValue,
|
|
18144
|
-
...childRest
|
|
18145
|
-
} = child;
|
|
18146
|
-
return jsx("option", {
|
|
18147
|
-
name: name,
|
|
18148
|
-
value: childValue,
|
|
18149
|
-
selected: childValue === value,
|
|
18150
|
-
readOnly: readOnly || childReadOnly,
|
|
18151
|
-
disabled: disabled || childDisabled,
|
|
18152
|
-
loading: loading || childLoading,
|
|
18153
|
-
...childRest,
|
|
18154
|
-
children: label
|
|
18155
|
-
}, childValue);
|
|
18156
|
-
})
|
|
18157
|
-
});
|
|
18158
|
-
return jsx(LoaderBackground, {
|
|
18159
|
-
loading: loading,
|
|
18160
|
-
color: "light-dark(#355fcc, #3b82f6)",
|
|
18161
|
-
inset: -1,
|
|
18162
|
-
children: selectElement
|
|
18163
|
-
});
|
|
18293
|
+
const Details = forwardRef((props, ref) => {
|
|
18294
|
+
return renderActionableComponent(props, ref);
|
|
18164
18295
|
});
|
|
18165
|
-
forwardRef((props, ref) => {
|
|
18296
|
+
const DetailsBasic = forwardRef((props, ref) => {
|
|
18166
18297
|
const {
|
|
18167
|
-
value: initialValue,
|
|
18168
18298
|
id,
|
|
18299
|
+
label = "Summary",
|
|
18300
|
+
open,
|
|
18301
|
+
loading,
|
|
18302
|
+
className,
|
|
18303
|
+
focusGroup,
|
|
18304
|
+
focusGroupDirection,
|
|
18305
|
+
arrowKeyShortcuts = true,
|
|
18306
|
+
openKeyShortcut = "ArrowRight",
|
|
18307
|
+
closeKeyShortcut = "ArrowLeft",
|
|
18308
|
+
onToggle,
|
|
18169
18309
|
children,
|
|
18170
18310
|
...rest
|
|
18171
18311
|
} = props;
|
|
18172
18312
|
const innerRef = useRef();
|
|
18173
18313
|
useImperativeHandle(ref, () => innerRef.current);
|
|
18174
18314
|
const [navState, setNavState] = useNavState(id);
|
|
18175
|
-
const
|
|
18176
|
-
|
|
18177
|
-
|
|
18178
|
-
|
|
18179
|
-
|
|
18180
|
-
return jsx(SelectControlled, {
|
|
18181
|
-
ref: innerRef,
|
|
18182
|
-
value: value,
|
|
18183
|
-
onChange: event => {
|
|
18184
|
-
const select = event.target;
|
|
18185
|
-
const selectedValue = select.value;
|
|
18186
|
-
setValue(selectedValue);
|
|
18187
|
-
},
|
|
18188
|
-
...rest,
|
|
18189
|
-
children: children
|
|
18190
|
-
});
|
|
18191
|
-
});
|
|
18192
|
-
forwardRef((props, ref) => {
|
|
18193
|
-
const {
|
|
18194
|
-
id,
|
|
18195
|
-
name,
|
|
18196
|
-
value: externalValue,
|
|
18197
|
-
valueSignal,
|
|
18198
|
-
action,
|
|
18199
|
-
children,
|
|
18200
|
-
onCancel,
|
|
18201
|
-
onActionPrevented,
|
|
18202
|
-
onActionStart,
|
|
18203
|
-
onActionAbort,
|
|
18204
|
-
onActionError,
|
|
18205
|
-
onActionEnd,
|
|
18206
|
-
actionErrorEffect,
|
|
18207
|
-
...rest
|
|
18208
|
-
} = props;
|
|
18209
|
-
const innerRef = useRef();
|
|
18210
|
-
useImperativeHandle(ref, () => innerRef.current);
|
|
18211
|
-
const [navState, setNavState, resetNavState] = useNavState(id);
|
|
18212
|
-
const [boundAction, value, setValue, initialValue] = useActionBoundToOneParam(action, name);
|
|
18213
|
-
const {
|
|
18214
|
-
loading: actionLoading
|
|
18215
|
-
} = useActionStatus(boundAction);
|
|
18216
|
-
const executeAction = useExecuteAction(innerRef, {
|
|
18217
|
-
errorEffect: actionErrorEffect
|
|
18218
|
-
});
|
|
18219
|
-
useEffect(() => {
|
|
18220
|
-
setNavState(value);
|
|
18221
|
-
}, [value]);
|
|
18222
|
-
const actionRequesterRef = useRef(null);
|
|
18223
|
-
useActionEvents(innerRef, {
|
|
18224
|
-
onCancel: (e, reason) => {
|
|
18225
|
-
resetNavState();
|
|
18226
|
-
setValue(initialValue);
|
|
18227
|
-
onCancel?.(e, reason);
|
|
18228
|
-
},
|
|
18229
|
-
onPrevented: onActionPrevented,
|
|
18230
|
-
onAction: actionEvent => {
|
|
18231
|
-
actionRequesterRef.current = actionEvent.detail.requester;
|
|
18232
|
-
executeAction(actionEvent);
|
|
18233
|
-
},
|
|
18234
|
-
onStart: onActionStart,
|
|
18235
|
-
onAbort: e => {
|
|
18236
|
-
setValue(initialValue);
|
|
18237
|
-
onActionAbort?.(e);
|
|
18238
|
-
},
|
|
18239
|
-
onError: error => {
|
|
18240
|
-
setValue(initialValue);
|
|
18241
|
-
onActionError?.(error);
|
|
18242
|
-
},
|
|
18243
|
-
onEnd: () => {
|
|
18244
|
-
resetNavState();
|
|
18245
|
-
onActionEnd?.();
|
|
18246
|
-
}
|
|
18315
|
+
const [innerOpen, innerOpenSetter] = useState(open || navState);
|
|
18316
|
+
useFocusGroup(innerRef, {
|
|
18317
|
+
enabled: focusGroup,
|
|
18318
|
+
name: typeof focusGroup === "string" ? focusGroup : undefined,
|
|
18319
|
+
direction: focusGroupDirection
|
|
18247
18320
|
});
|
|
18248
|
-
|
|
18249
|
-
|
|
18250
|
-
|
|
18251
|
-
|
|
18252
|
-
|
|
18253
|
-
|
|
18254
|
-
|
|
18255
|
-
|
|
18256
|
-
|
|
18257
|
-
|
|
18258
|
-
|
|
18259
|
-
|
|
18260
|
-
|
|
18261
|
-
|
|
18262
|
-
|
|
18321
|
+
|
|
18322
|
+
/**
|
|
18323
|
+
* Browser will dispatch "toggle" event even if we set open={true}
|
|
18324
|
+
* When rendering the component for the first time
|
|
18325
|
+
* We have to ensure the initial "toggle" event is ignored.
|
|
18326
|
+
*
|
|
18327
|
+
* If we don't do that code will think the details has changed and run logic accordingly
|
|
18328
|
+
* For example it will try to navigate to the current url while we are already there
|
|
18329
|
+
*
|
|
18330
|
+
* See:
|
|
18331
|
+
* - https://techblog.thescore.com/2024/10/08/why-we-decided-to-change-how-the-details-element-works/
|
|
18332
|
+
* - https://github.com/whatwg/html/issues/4500
|
|
18333
|
+
* - https://stackoverflow.com/questions/58942600/react-html-details-toggles-uncontrollably-when-starts-open
|
|
18334
|
+
*
|
|
18335
|
+
*/
|
|
18336
|
+
|
|
18337
|
+
const summaryRef = useRef(null);
|
|
18338
|
+
useKeyboardShortcuts(innerRef, [{
|
|
18339
|
+
key: openKeyShortcut,
|
|
18340
|
+
enabled: arrowKeyShortcuts,
|
|
18341
|
+
when: e => document.activeElement === summaryRef.current &&
|
|
18342
|
+
// avoid handling openKeyShortcut twice when keydown occurs inside nested details
|
|
18343
|
+
!e.defaultPrevented,
|
|
18344
|
+
action: e => {
|
|
18345
|
+
const details = innerRef.current;
|
|
18346
|
+
if (!details.open) {
|
|
18347
|
+
e.preventDefault();
|
|
18348
|
+
details.open = true;
|
|
18349
|
+
return;
|
|
18350
|
+
}
|
|
18351
|
+
const summary = summaryRef.current;
|
|
18352
|
+
const firstFocusableElementInDetails = findAfter(summary, elementIsFocusable, {
|
|
18353
|
+
root: details
|
|
18263
18354
|
});
|
|
18355
|
+
if (!firstFocusableElementInDetails) {
|
|
18356
|
+
return;
|
|
18357
|
+
}
|
|
18358
|
+
e.preventDefault();
|
|
18359
|
+
firstFocusableElementInDetails.focus();
|
|
18360
|
+
}
|
|
18361
|
+
}, {
|
|
18362
|
+
key: closeKeyShortcut,
|
|
18363
|
+
enabled: arrowKeyShortcuts,
|
|
18364
|
+
when: () => {
|
|
18365
|
+
const details = innerRef.current;
|
|
18366
|
+
return details.open;
|
|
18264
18367
|
},
|
|
18368
|
+
action: e => {
|
|
18369
|
+
const details = innerRef.current;
|
|
18370
|
+
const summary = summaryRef.current;
|
|
18371
|
+
if (document.activeElement === summary) {
|
|
18372
|
+
e.preventDefault();
|
|
18373
|
+
summary.focus();
|
|
18374
|
+
details.open = false;
|
|
18375
|
+
} else {
|
|
18376
|
+
e.preventDefault();
|
|
18377
|
+
summary.focus();
|
|
18378
|
+
}
|
|
18379
|
+
}
|
|
18380
|
+
}]);
|
|
18381
|
+
const mountedRef = useRef(false);
|
|
18382
|
+
useEffect(() => {
|
|
18383
|
+
mountedRef.current = true;
|
|
18384
|
+
}, []);
|
|
18385
|
+
return jsxs("details", {
|
|
18265
18386
|
...rest,
|
|
18266
|
-
|
|
18267
|
-
|
|
18268
|
-
|
|
18269
|
-
|
|
18270
|
-
|
|
18271
|
-
|
|
18272
|
-
|
|
18273
|
-
|
|
18274
|
-
|
|
18387
|
+
ref: innerRef,
|
|
18388
|
+
id: id,
|
|
18389
|
+
className: ["navi_details", ...(className ? className.split(" ") : [])].join(" "),
|
|
18390
|
+
onToggle: e => {
|
|
18391
|
+
const isOpen = e.newState === "open";
|
|
18392
|
+
if (mountedRef.current) {
|
|
18393
|
+
if (isOpen) {
|
|
18394
|
+
innerOpenSetter(true);
|
|
18395
|
+
setNavState(true);
|
|
18396
|
+
} else {
|
|
18397
|
+
innerOpenSetter(false);
|
|
18398
|
+
setNavState(undefined);
|
|
18399
|
+
}
|
|
18400
|
+
}
|
|
18401
|
+
onToggle?.(e);
|
|
18402
|
+
},
|
|
18403
|
+
open: innerOpen,
|
|
18404
|
+
children: [jsx("summary", {
|
|
18405
|
+
ref: summaryRef,
|
|
18406
|
+
children: jsxs("div", {
|
|
18407
|
+
className: "summary_body",
|
|
18408
|
+
children: [jsx(SummaryMarker, {
|
|
18409
|
+
open: innerOpen,
|
|
18410
|
+
loading: loading
|
|
18411
|
+
}), jsx("div", {
|
|
18412
|
+
className: "summary_label",
|
|
18413
|
+
children: label
|
|
18414
|
+
})]
|
|
18415
|
+
})
|
|
18416
|
+
}), children]
|
|
18275
18417
|
});
|
|
18276
18418
|
});
|
|
18277
18419
|
forwardRef((props, ref) => {
|
|
18278
18420
|
const {
|
|
18279
|
-
|
|
18280
|
-
|
|
18281
|
-
|
|
18421
|
+
action,
|
|
18422
|
+
loading,
|
|
18423
|
+
onToggle,
|
|
18424
|
+
onActionPrevented,
|
|
18425
|
+
onActionStart,
|
|
18426
|
+
onActionError,
|
|
18427
|
+
onActionEnd,
|
|
18282
18428
|
children,
|
|
18283
18429
|
...rest
|
|
18284
18430
|
} = props;
|
|
18285
18431
|
const innerRef = useRef();
|
|
18286
18432
|
useImperativeHandle(ref, () => innerRef.current);
|
|
18287
|
-
const
|
|
18288
|
-
const
|
|
18289
|
-
|
|
18290
|
-
|
|
18291
|
-
|
|
18292
|
-
|
|
18293
|
-
|
|
18294
|
-
|
|
18295
|
-
|
|
18296
|
-
|
|
18297
|
-
|
|
18433
|
+
const effectiveAction = useAction(action);
|
|
18434
|
+
const {
|
|
18435
|
+
loading: actionLoading
|
|
18436
|
+
} = useActionStatus(effectiveAction);
|
|
18437
|
+
const executeAction = useExecuteAction(innerRef, {
|
|
18438
|
+
// the error will be displayed by actionRenderer inside <details>
|
|
18439
|
+
errorEffect: "none"
|
|
18440
|
+
});
|
|
18441
|
+
useActionEvents(innerRef, {
|
|
18442
|
+
onPrevented: onActionPrevented,
|
|
18443
|
+
onAction: e => {
|
|
18444
|
+
executeAction(e);
|
|
18298
18445
|
},
|
|
18299
|
-
|
|
18300
|
-
|
|
18301
|
-
|
|
18446
|
+
onStart: onActionStart,
|
|
18447
|
+
onError: onActionError,
|
|
18448
|
+
onEnd: onActionEnd
|
|
18302
18449
|
});
|
|
18303
|
-
return jsx(
|
|
18450
|
+
return jsx(DetailsBasic, {
|
|
18451
|
+
...rest,
|
|
18304
18452
|
ref: innerRef,
|
|
18305
|
-
|
|
18306
|
-
|
|
18307
|
-
|
|
18308
|
-
|
|
18309
|
-
|
|
18310
|
-
|
|
18453
|
+
loading: loading || actionLoading,
|
|
18454
|
+
onToggle: toggleEvent => {
|
|
18455
|
+
const isOpen = toggleEvent.newState === "open";
|
|
18456
|
+
if (isOpen) {
|
|
18457
|
+
requestAction(toggleEvent.target, effectiveAction, {
|
|
18458
|
+
event: toggleEvent,
|
|
18459
|
+
method: "run"
|
|
18460
|
+
});
|
|
18461
|
+
} else {
|
|
18462
|
+
effectiveAction.abort();
|
|
18463
|
+
}
|
|
18464
|
+
onToggle?.(toggleEvent);
|
|
18311
18465
|
},
|
|
18312
|
-
|
|
18313
|
-
|
|
18466
|
+
children: jsx(ActionRenderer, {
|
|
18467
|
+
action: effectiveAction,
|
|
18468
|
+
children: children
|
|
18469
|
+
})
|
|
18314
18470
|
});
|
|
18315
18471
|
});
|
|
18316
18472
|
|
|
@@ -21678,116 +21834,6 @@ const useCellsAndColumns = (cells, columns) => {
|
|
|
21678
21834
|
};
|
|
21679
21835
|
};
|
|
21680
21836
|
|
|
21681
|
-
installImportMetaCss(import.meta);import.meta.css = /* css */`
|
|
21682
|
-
.navi_tablist {
|
|
21683
|
-
display: flex;
|
|
21684
|
-
overflow-x: auto;
|
|
21685
|
-
overflow-y: hidden;
|
|
21686
|
-
justify-content: space-between;
|
|
21687
|
-
}
|
|
21688
|
-
|
|
21689
|
-
.navi_tablist > ul {
|
|
21690
|
-
align-items: center;
|
|
21691
|
-
display: flex;
|
|
21692
|
-
gap: 0.5rem;
|
|
21693
|
-
list-style: none;
|
|
21694
|
-
margin: 0;
|
|
21695
|
-
padding: 0;
|
|
21696
|
-
}
|
|
21697
|
-
|
|
21698
|
-
.navi_tablist > ul > li {
|
|
21699
|
-
display: inline-flex;
|
|
21700
|
-
position: relative;
|
|
21701
|
-
}
|
|
21702
|
-
|
|
21703
|
-
.navi_tab {
|
|
21704
|
-
white-space: nowrap;
|
|
21705
|
-
display: flex;
|
|
21706
|
-
flex-direction: column;
|
|
21707
|
-
}
|
|
21708
|
-
|
|
21709
|
-
.navi_tab_content {
|
|
21710
|
-
transition: background 0.12s ease-out;
|
|
21711
|
-
border-radius: 6px;
|
|
21712
|
-
text-decoration: none;
|
|
21713
|
-
line-height: 30px;
|
|
21714
|
-
display: flex;
|
|
21715
|
-
padding: 0 0.5rem;
|
|
21716
|
-
}
|
|
21717
|
-
|
|
21718
|
-
.navi_tab:hover .navi_tab_content {
|
|
21719
|
-
background: #dae0e7;
|
|
21720
|
-
color: #010409;
|
|
21721
|
-
}
|
|
21722
|
-
|
|
21723
|
-
.navi_tab .active_marker {
|
|
21724
|
-
display: flex;
|
|
21725
|
-
background: transparent;
|
|
21726
|
-
border-radius: 0.1px;
|
|
21727
|
-
width: 100%;
|
|
21728
|
-
z-index: 1;
|
|
21729
|
-
height: 2px;
|
|
21730
|
-
margin-top: 5px;
|
|
21731
|
-
}
|
|
21732
|
-
|
|
21733
|
-
/* Hidden bold clone to reserve space for bold width without affecting height */
|
|
21734
|
-
.navi_tab_content_bold_clone {
|
|
21735
|
-
font-weight: 600; /* force bold to compute max width */
|
|
21736
|
-
visibility: hidden; /* not visible */
|
|
21737
|
-
display: block; /* in-flow so it contributes to width */
|
|
21738
|
-
height: 0; /* zero height so it doesn't change layout height */
|
|
21739
|
-
overflow: hidden; /* avoid any accidental height */
|
|
21740
|
-
pointer-events: none; /* inert */
|
|
21741
|
-
}
|
|
21742
|
-
|
|
21743
|
-
.navi_tab[aria-selected="true"] .active_marker {
|
|
21744
|
-
background: rgb(205, 52, 37);
|
|
21745
|
-
}
|
|
21746
|
-
|
|
21747
|
-
.navi_tab[aria-selected="true"] .navi_tab_content {
|
|
21748
|
-
font-weight: 600;
|
|
21749
|
-
}
|
|
21750
|
-
`;
|
|
21751
|
-
const TabList = ({
|
|
21752
|
-
children,
|
|
21753
|
-
...props
|
|
21754
|
-
}) => {
|
|
21755
|
-
return jsx("nav", {
|
|
21756
|
-
className: "navi_tablist",
|
|
21757
|
-
role: "tablist",
|
|
21758
|
-
...props,
|
|
21759
|
-
children: jsx("ul", {
|
|
21760
|
-
children: children.map(child => {
|
|
21761
|
-
return jsx("li", {
|
|
21762
|
-
children: child
|
|
21763
|
-
}, child.props.key);
|
|
21764
|
-
})
|
|
21765
|
-
})
|
|
21766
|
-
});
|
|
21767
|
-
};
|
|
21768
|
-
const Tab = ({
|
|
21769
|
-
children,
|
|
21770
|
-
selected,
|
|
21771
|
-
...props
|
|
21772
|
-
}) => {
|
|
21773
|
-
return jsxs("div", {
|
|
21774
|
-
className: "navi_tab",
|
|
21775
|
-
role: "tab",
|
|
21776
|
-
"aria-selected": selected ? "true" : "false",
|
|
21777
|
-
...props,
|
|
21778
|
-
children: [jsx("div", {
|
|
21779
|
-
className: "navi_tab_content",
|
|
21780
|
-
children: children
|
|
21781
|
-
}), jsx("div", {
|
|
21782
|
-
className: "navi_tab_content_bold_clone",
|
|
21783
|
-
"aria-hidden": "true",
|
|
21784
|
-
children: children
|
|
21785
|
-
}), jsx("span", {
|
|
21786
|
-
className: "active_marker"
|
|
21787
|
-
})]
|
|
21788
|
-
});
|
|
21789
|
-
};
|
|
21790
|
-
|
|
21791
21837
|
/**
|
|
21792
21838
|
* Creates a signal that stays synchronized with an external value,
|
|
21793
21839
|
* only updating the signal when the value actually changes.
|
|
@@ -22357,48 +22403,6 @@ const ViewportLayout = props => {
|
|
|
22357
22403
|
});
|
|
22358
22404
|
};
|
|
22359
22405
|
|
|
22360
|
-
const createUniqueValueConstraint = (
|
|
22361
|
-
// the set might be incomplete (the front usually don't have the full copy of all the items from the backend)
|
|
22362
|
-
// but this is already nice to help user with what we know
|
|
22363
|
-
// it's also possible that front is unsync with backend, preventing user to choose a value
|
|
22364
|
-
// that is actually free.
|
|
22365
|
-
// But this is unlikely to happen and user could reload the page to be able to choose that name
|
|
22366
|
-
// that suddenly became available
|
|
22367
|
-
existingValueSet,
|
|
22368
|
-
message = `"{value}" already exists. Please choose another value.`,
|
|
22369
|
-
) => {
|
|
22370
|
-
return {
|
|
22371
|
-
name: "unique_value",
|
|
22372
|
-
check: (input) => {
|
|
22373
|
-
const inputValue = input.value;
|
|
22374
|
-
const hasConflict = existingValueSet.has(inputValue);
|
|
22375
|
-
// console.log({
|
|
22376
|
-
// inputValue,
|
|
22377
|
-
// names: Array.from(otherNameSet.values()),
|
|
22378
|
-
// hasConflict,
|
|
22379
|
-
// });
|
|
22380
|
-
if (hasConflict) {
|
|
22381
|
-
return message.replace("{value}", inputValue);
|
|
22382
|
-
}
|
|
22383
|
-
return "";
|
|
22384
|
-
},
|
|
22385
|
-
};
|
|
22386
|
-
};
|
|
22387
|
-
|
|
22388
|
-
const SINGLE_SPACE_CONSTRAINT = {
|
|
22389
|
-
name: "single_space",
|
|
22390
|
-
check: (input) => {
|
|
22391
|
-
const inputValue = input.value;
|
|
22392
|
-
const hasLeadingSpace = inputValue.startsWith(" ");
|
|
22393
|
-
const hasTrailingSpace = inputValue.endsWith(" ");
|
|
22394
|
-
const hasDoubleSpace = inputValue.includes(" ");
|
|
22395
|
-
if (hasLeadingSpace || hasDoubleSpace || hasTrailingSpace) {
|
|
22396
|
-
return "Spaces at the beginning, end, or consecutive spaces are not allowed";
|
|
22397
|
-
}
|
|
22398
|
-
return "";
|
|
22399
|
-
},
|
|
22400
|
-
};
|
|
22401
|
-
|
|
22402
22406
|
/*
|
|
22403
22407
|
* - Usage
|
|
22404
22408
|
* useEffect(() => {
|