@octaviaflow/core 3.0.4 → 3.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Button/Button.d.ts.map +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/Dialog/Dialog.d.ts.map +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.d.ts +9 -1
- package/dist/components/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/components/Radio/Radio.d.ts.map +1 -1
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/SlideoutPanel/SlideoutPanel.d.ts.map +1 -1
- package/dist/components/Switch/Switch.d.ts.map +1 -1
- package/dist/components/Textarea/Textarea.d.ts.map +1 -1
- package/dist/index.cjs +132 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +136 -35
- package/dist/index.js.map +1 -1
- package/dist/stories/state-matrix.d.ts +74 -0
- package/dist/stories/state-matrix.d.ts.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/utils/a11y.d.ts +70 -0
- package/dist/utils/a11y.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -607,6 +607,32 @@ function Breadcrumb({
|
|
|
607
607
|
import { motion as motion2 } from "framer-motion";
|
|
608
608
|
import { useRef as useRef3 } from "react";
|
|
609
609
|
import { useButton } from "react-aria";
|
|
610
|
+
|
|
611
|
+
// src/utils/a11y.ts
|
|
612
|
+
function resolveAccessibleName(input) {
|
|
613
|
+
if (input.ariaLabelledby) {
|
|
614
|
+
return { "aria-labelledby": input.ariaLabelledby };
|
|
615
|
+
}
|
|
616
|
+
if (input.ariaLabel) {
|
|
617
|
+
return { "aria-label": input.ariaLabel };
|
|
618
|
+
}
|
|
619
|
+
if (typeof input.label === "string" && input.label.trim().length > 0) {
|
|
620
|
+
return { "aria-label": input.label };
|
|
621
|
+
}
|
|
622
|
+
for (const candidate of input.fallbacks ?? []) {
|
|
623
|
+
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
624
|
+
return { "aria-label": candidate };
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
if (process.env.NODE_ENV !== "production") {
|
|
628
|
+
console.error(
|
|
629
|
+
`[@octaviaflow/core ${input.componentName}] No accessible name. Pass a string \`label\`, or \`aria-label\`, or \`aria-labelledby\` so screen readers can announce this control.`
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
return { "aria-label": `Unlabeled ${input.componentName}` };
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// src/components/Button/Button.tsx
|
|
610
636
|
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
611
637
|
function Button({
|
|
612
638
|
variant = "primary",
|
|
@@ -624,11 +650,19 @@ function Button({
|
|
|
624
650
|
const ref = useRef3(null);
|
|
625
651
|
const isDisabled = disabled || loading;
|
|
626
652
|
const resolvedType = type ?? "button";
|
|
653
|
+
const hasVisibleText = typeof children === "string" ? children.trim().length > 0 : Boolean(children);
|
|
654
|
+
const needsAriaName = !hasVisibleText;
|
|
655
|
+
const ariaNameProps = needsAriaName ? resolveAccessibleName({
|
|
656
|
+
ariaLabel: props["aria-label"],
|
|
657
|
+
ariaLabelledby: props["aria-labelledby"],
|
|
658
|
+
componentName: "Button"
|
|
659
|
+
}) : void 0;
|
|
627
660
|
const { buttonProps } = useButton(
|
|
628
661
|
{
|
|
629
662
|
isDisabled,
|
|
630
663
|
onPress: props.onClick,
|
|
631
|
-
type: resolvedType
|
|
664
|
+
type: resolvedType,
|
|
665
|
+
...ariaNameProps ?? {}
|
|
632
666
|
},
|
|
633
667
|
ref
|
|
634
668
|
);
|
|
@@ -644,7 +678,7 @@ function Button({
|
|
|
644
678
|
onBlur: _onBlur,
|
|
645
679
|
...passthroughProps
|
|
646
680
|
} = props;
|
|
647
|
-
return /* @__PURE__ */
|
|
681
|
+
return /* @__PURE__ */ jsx10(
|
|
648
682
|
motion2.button,
|
|
649
683
|
{
|
|
650
684
|
...passthroughProps,
|
|
@@ -662,27 +696,32 @@ function Button({
|
|
|
662
696
|
"data-loading": loading || void 0,
|
|
663
697
|
whileTap: isDisabled ? void 0 : { scale: 0.97 },
|
|
664
698
|
transition: { duration: 0.1 },
|
|
665
|
-
children: [
|
|
666
|
-
/* @__PURE__ */
|
|
667
|
-
|
|
668
|
-
children && /* @__PURE__ */ jsx10("span", { className: "ods-btn__label", children }),
|
|
669
|
-
rightIcon && /* @__PURE__ */ jsx10("span", { className: "ods-btn__icon ods-btn__icon--right", children: rightIcon })
|
|
670
|
-
] }),
|
|
671
|
-
loading && /* @__PURE__ */ jsx10("span", { className: "ods-btn__spinner", role: "status", "aria-label": "Loading", children: /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", width: "16", height: "16", "aria-hidden": "true", children: /* @__PURE__ */ jsx10(
|
|
672
|
-
"circle",
|
|
699
|
+
children: /* @__PURE__ */ jsxs10("span", { className: "ods-btn__content", children: [
|
|
700
|
+
loading ? /* @__PURE__ */ jsx10(
|
|
701
|
+
"span",
|
|
673
702
|
{
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
703
|
+
className: "ods-btn__icon ods-btn__icon--left ods-btn__icon--spinner",
|
|
704
|
+
role: "status",
|
|
705
|
+
"aria-label": "Loading",
|
|
706
|
+
children: /* @__PURE__ */ jsx10("svg", { viewBox: "0 0 24 24", width: "16", height: "16", "aria-hidden": "true", children: /* @__PURE__ */ jsx10(
|
|
707
|
+
"circle",
|
|
708
|
+
{
|
|
709
|
+
cx: "12",
|
|
710
|
+
cy: "12",
|
|
711
|
+
r: "10",
|
|
712
|
+
fill: "none",
|
|
713
|
+
stroke: "currentColor",
|
|
714
|
+
strokeWidth: "2.5",
|
|
715
|
+
strokeLinecap: "round",
|
|
716
|
+
strokeDasharray: "32",
|
|
717
|
+
strokeDashoffset: "12"
|
|
718
|
+
}
|
|
719
|
+
) })
|
|
683
720
|
}
|
|
684
|
-
)
|
|
685
|
-
|
|
721
|
+
) : leftIcon && /* @__PURE__ */ jsx10("span", { className: "ods-btn__icon ods-btn__icon--left", children: leftIcon }),
|
|
722
|
+
children && /* @__PURE__ */ jsx10("span", { className: "ods-btn__label", children }),
|
|
723
|
+
rightIcon && !loading && /* @__PURE__ */ jsx10("span", { className: "ods-btn__icon ods-btn__icon--right", children: rightIcon })
|
|
724
|
+
] })
|
|
686
725
|
}
|
|
687
726
|
);
|
|
688
727
|
}
|
|
@@ -2454,13 +2493,19 @@ function Checkbox({
|
|
|
2454
2493
|
defaultSelected: defaultChecked,
|
|
2455
2494
|
onChange
|
|
2456
2495
|
});
|
|
2496
|
+
const ariaNameProps = resolveAccessibleName({
|
|
2497
|
+
label,
|
|
2498
|
+
ariaLabel: props["aria-label"],
|
|
2499
|
+
ariaLabelledby: props["aria-labelledby"],
|
|
2500
|
+
componentName: "Checkbox"
|
|
2501
|
+
});
|
|
2457
2502
|
const { inputProps } = useCheckbox(
|
|
2458
2503
|
{
|
|
2459
2504
|
isSelected: state.isSelected,
|
|
2460
2505
|
isIndeterminate: indeterminate,
|
|
2461
2506
|
isDisabled: disabled,
|
|
2462
2507
|
onChange,
|
|
2463
|
-
|
|
2508
|
+
...ariaNameProps
|
|
2464
2509
|
},
|
|
2465
2510
|
state,
|
|
2466
2511
|
ref
|
|
@@ -6010,7 +6055,7 @@ function DescriptionList({
|
|
|
6010
6055
|
// src/components/Dialog/Dialog.tsx
|
|
6011
6056
|
import { AnimatePresence as AnimatePresence3, motion as motion5 } from "framer-motion";
|
|
6012
6057
|
import { useRef as useRef11 } from "react";
|
|
6013
|
-
import { FocusScope, useDialog, useModal, useOverlay } from "react-aria";
|
|
6058
|
+
import { FocusScope, OverlayProvider, useDialog, useModal, useOverlay } from "react-aria";
|
|
6014
6059
|
import { createPortal } from "react-dom";
|
|
6015
6060
|
|
|
6016
6061
|
// src/utils/motion.ts
|
|
@@ -6130,7 +6175,10 @@ function DialogContent({
|
|
|
6130
6175
|
}
|
|
6131
6176
|
function Dialog(props) {
|
|
6132
6177
|
if (typeof document === "undefined") return null;
|
|
6133
|
-
return createPortal(
|
|
6178
|
+
return createPortal(
|
|
6179
|
+
/* @__PURE__ */ jsx26(OverlayProvider, { children: /* @__PURE__ */ jsx26(DialogContent, { ...props }) }),
|
|
6180
|
+
document.body
|
|
6181
|
+
);
|
|
6134
6182
|
}
|
|
6135
6183
|
|
|
6136
6184
|
// src/components/DonutChart/DonutChart.tsx
|
|
@@ -6360,11 +6408,27 @@ function MenuPopup({
|
|
|
6360
6408
|
}
|
|
6361
6409
|
return null;
|
|
6362
6410
|
}
|
|
6363
|
-
function DropdownMenu({
|
|
6411
|
+
function DropdownMenu({
|
|
6412
|
+
trigger,
|
|
6413
|
+
items,
|
|
6414
|
+
align = "start",
|
|
6415
|
+
className,
|
|
6416
|
+
"aria-label": ariaLabel,
|
|
6417
|
+
"aria-labelledby": ariaLabelledby
|
|
6418
|
+
}) {
|
|
6364
6419
|
const triggerRef = useRef12(null);
|
|
6365
6420
|
const state = $e3403870bfb691da$export$79fefeb1c2091ac3({});
|
|
6366
6421
|
const { menuTriggerProps } = useMenuTrigger({}, state, triggerRef);
|
|
6367
|
-
const
|
|
6422
|
+
const ariaNameProps = resolveAccessibleName({
|
|
6423
|
+
ariaLabel,
|
|
6424
|
+
ariaLabelledby,
|
|
6425
|
+
componentName: "DropdownMenu",
|
|
6426
|
+
fallbacks: [typeof trigger === "string" ? trigger : void 0]
|
|
6427
|
+
});
|
|
6428
|
+
const { buttonProps } = useButton3(
|
|
6429
|
+
{ ...menuTriggerProps, ...ariaNameProps },
|
|
6430
|
+
triggerRef
|
|
6431
|
+
);
|
|
6368
6432
|
const { onDrag, onDragStart, onDragEnd, onAnimationStart, ...safeTriggerProps } = buttonProps;
|
|
6369
6433
|
return /* @__PURE__ */ jsxs28(Fragment6, { children: [
|
|
6370
6434
|
/* @__PURE__ */ jsx29("button", { ...safeTriggerProps, ref: triggerRef, className: "ods-dropdown__trigger", children: trigger }),
|
|
@@ -10178,11 +10242,18 @@ function Radio({
|
|
|
10178
10242
|
}) {
|
|
10179
10243
|
const state = useRadioGroupContext();
|
|
10180
10244
|
const ref = useRef24(null);
|
|
10245
|
+
const ariaNameProps = resolveAccessibleName({
|
|
10246
|
+
label,
|
|
10247
|
+
ariaLabel: props["aria-label"],
|
|
10248
|
+
ariaLabelledby: props["aria-labelledby"],
|
|
10249
|
+
componentName: "Radio",
|
|
10250
|
+
fallbacks: [value]
|
|
10251
|
+
});
|
|
10181
10252
|
const { inputProps } = useRadio(
|
|
10182
10253
|
{
|
|
10183
10254
|
value,
|
|
10184
10255
|
isDisabled: disabled,
|
|
10185
|
-
|
|
10256
|
+
...ariaNameProps
|
|
10186
10257
|
},
|
|
10187
10258
|
state,
|
|
10188
10259
|
ref
|
|
@@ -10780,6 +10851,15 @@ function Select({
|
|
|
10780
10851
|
(o) => o.label.toLowerCase().includes(q) || o.description?.toLowerCase().includes(q)
|
|
10781
10852
|
);
|
|
10782
10853
|
}, [options, searchQuery, searchable]);
|
|
10854
|
+
const ariaNameProps = useMemo10(
|
|
10855
|
+
() => resolveAccessibleName({
|
|
10856
|
+
label,
|
|
10857
|
+
ariaLabel,
|
|
10858
|
+
ariaLabelledby: ariaLabelledBy,
|
|
10859
|
+
componentName: "Select"
|
|
10860
|
+
}),
|
|
10861
|
+
[label, ariaLabel, ariaLabelledBy]
|
|
10862
|
+
);
|
|
10783
10863
|
const ariaProps = useMemo10(() => {
|
|
10784
10864
|
const items = filteredOptions.map((o) => ({
|
|
10785
10865
|
key: o.value,
|
|
@@ -10788,7 +10868,10 @@ function Select({
|
|
|
10788
10868
|
isDisabled: o.disabled
|
|
10789
10869
|
}));
|
|
10790
10870
|
const props = {
|
|
10791
|
-
|
|
10871
|
+
// Visible string label when present; otherwise rely on the aria-*
|
|
10872
|
+
// props for screen-reader name.
|
|
10873
|
+
label: typeof label === "string" ? label : void 0,
|
|
10874
|
+
...ariaNameProps,
|
|
10792
10875
|
items,
|
|
10793
10876
|
children: (item) => /* @__PURE__ */ jsx66($05678f3aee5e7d1a$export$6d08773d2e66f8f2, { textValue: item.label, children: item.label }, item.key),
|
|
10794
10877
|
isDisabled: disabled,
|
|
@@ -10804,7 +10887,7 @@ function Select({
|
|
|
10804
10887
|
props.defaultSelectedKey = defaultValue;
|
|
10805
10888
|
}
|
|
10806
10889
|
return props;
|
|
10807
|
-
}, [filteredOptions, label, disabled, value, defaultValue, onChange]);
|
|
10890
|
+
}, [filteredOptions, label, disabled, value, defaultValue, onChange, ariaNameProps]);
|
|
10808
10891
|
const state = $29256f53a2edafe9$export$5159ec8b34d4ec12(ariaProps);
|
|
10809
10892
|
const { triggerProps, menuProps } = useSelect(ariaProps, state, triggerRef);
|
|
10810
10893
|
const { buttonProps } = useButton4(triggerProps, triggerRef);
|
|
@@ -11476,7 +11559,7 @@ function Skeleton({ variant = "text", width, height, lines = 1, className }) {
|
|
|
11476
11559
|
// src/components/SlideoutPanel/SlideoutPanel.tsx
|
|
11477
11560
|
import { AnimatePresence as AnimatePresence9, motion as motion12 } from "framer-motion";
|
|
11478
11561
|
import { useRef as useRef28 } from "react";
|
|
11479
|
-
import { FocusScope as FocusScope2, useDialog as useDialog2, useModal as useModal2, useOverlay as useOverlay2 } from "react-aria";
|
|
11562
|
+
import { FocusScope as FocusScope2, OverlayProvider as OverlayProvider2, useDialog as useDialog2, useModal as useModal2, useOverlay as useOverlay2 } from "react-aria";
|
|
11480
11563
|
import { createPortal as createPortal8 } from "react-dom";
|
|
11481
11564
|
import { Fragment as Fragment16, jsx as jsx71, jsxs as jsxs69 } from "react/jsx-runtime";
|
|
11482
11565
|
var slideVariants2 = {
|
|
@@ -11569,7 +11652,10 @@ function SlideoutContent({
|
|
|
11569
11652
|
}
|
|
11570
11653
|
function SlideoutPanel(props) {
|
|
11571
11654
|
if (typeof document === "undefined") return null;
|
|
11572
|
-
return createPortal8(
|
|
11655
|
+
return createPortal8(
|
|
11656
|
+
/* @__PURE__ */ jsx71(OverlayProvider2, { children: /* @__PURE__ */ jsx71(SlideoutContent, { ...props }) }),
|
|
11657
|
+
document.body
|
|
11658
|
+
);
|
|
11573
11659
|
}
|
|
11574
11660
|
|
|
11575
11661
|
// src/components/Slider/Slider.tsx
|
|
@@ -12160,12 +12246,18 @@ function Switch({
|
|
|
12160
12246
|
defaultSelected: defaultChecked,
|
|
12161
12247
|
onChange
|
|
12162
12248
|
});
|
|
12249
|
+
const ariaNameProps = resolveAccessibleName({
|
|
12250
|
+
label,
|
|
12251
|
+
ariaLabel: props["aria-label"],
|
|
12252
|
+
ariaLabelledby: props["aria-labelledby"],
|
|
12253
|
+
componentName: "Switch"
|
|
12254
|
+
});
|
|
12163
12255
|
const { inputProps } = useSwitch(
|
|
12164
12256
|
{
|
|
12165
12257
|
isSelected: state.isSelected,
|
|
12166
12258
|
isDisabled: disabled,
|
|
12167
12259
|
onChange,
|
|
12168
|
-
|
|
12260
|
+
...ariaNameProps
|
|
12169
12261
|
},
|
|
12170
12262
|
state,
|
|
12171
12263
|
ref
|
|
@@ -12611,9 +12703,18 @@ function Textarea({
|
|
|
12611
12703
|
const ref = useRef32(null);
|
|
12612
12704
|
const errorId = useId4();
|
|
12613
12705
|
const [charCount, setCharCount] = useState26(() => String(value ?? defaultValue ?? "").length);
|
|
12706
|
+
const ariaNameProps = resolveAccessibleName({
|
|
12707
|
+
label,
|
|
12708
|
+
ariaLabel: props["aria-label"],
|
|
12709
|
+
ariaLabelledby: props["aria-labelledby"],
|
|
12710
|
+
componentName: "Textarea"
|
|
12711
|
+
});
|
|
12614
12712
|
const { labelProps, inputProps } = useTextField2(
|
|
12615
12713
|
{
|
|
12616
|
-
|
|
12714
|
+
// Pass a string `label` only when caller gave a string; otherwise rely
|
|
12715
|
+
// on the aria-* props from resolveAccessibleName.
|
|
12716
|
+
label: typeof label === "string" ? label : void 0,
|
|
12717
|
+
...ariaNameProps,
|
|
12617
12718
|
isDisabled: disabled,
|
|
12618
12719
|
errorMessage,
|
|
12619
12720
|
validationState: error ? "invalid" : void 0,
|
|
@@ -15504,7 +15605,7 @@ function YamlViewer({
|
|
|
15504
15605
|
// src/provider/OdsProvider.tsx
|
|
15505
15606
|
import { generateCssVars, resolveConfig } from "@octaviaflow/config";
|
|
15506
15607
|
import { createContext as createContext3, useContext as useContext3, useEffect as useEffect21, useMemo as useMemo18 } from "react";
|
|
15507
|
-
import { OverlayProvider } from "react-aria";
|
|
15608
|
+
import { OverlayProvider as OverlayProvider3 } from "react-aria";
|
|
15508
15609
|
import { jsx as jsx98 } from "react/jsx-runtime";
|
|
15509
15610
|
var OdsContext = createContext3(null);
|
|
15510
15611
|
function OdsProvider({ config: userConfig, children }) {
|
|
@@ -15526,7 +15627,7 @@ function OdsProvider({ config: userConfig, children }) {
|
|
|
15526
15627
|
}
|
|
15527
15628
|
}, [resolved]);
|
|
15528
15629
|
const contextValue = useMemo18(() => ({ config: resolved }), [resolved]);
|
|
15529
|
-
return /* @__PURE__ */ jsx98(OdsContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx98(
|
|
15630
|
+
return /* @__PURE__ */ jsx98(OdsContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx98(OverlayProvider3, { children }) });
|
|
15530
15631
|
}
|
|
15531
15632
|
function useOds() {
|
|
15532
15633
|
const ctx = useContext3(OdsContext);
|