@tensor_1/react 2.30.0 → 2.32.0
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/README.md +430 -0
- package/dist/attachment-labels.d.ts +16 -0
- package/dist/attachment-labels.js +9 -0
- package/dist/calendar-model.d.ts +141 -1
- package/dist/calendar-model.js +200 -11
- package/dist/chart-preset.cjs +127 -7
- package/dist/chart-preset.d.cts +2 -2
- package/dist/chart-preset.d.ts +1 -0
- package/dist/chart-preset.js +6 -1
- package/dist/chart-theme-Cl0IrkKQ.d.cts +112 -0
- package/dist/chart-theme.d.ts +51 -0
- package/dist/chart-theme.js +99 -0
- package/dist/chart.cjs +127 -7
- package/dist/chart.d.cts +2 -2
- package/dist/chart.d.ts +1 -0
- package/dist/chart.js +6 -2
- package/dist/components/Alert.d.ts +17 -1
- package/dist/components/Alert.js +9 -4
- package/dist/components/AlertDismiss.d.ts +14 -0
- package/dist/components/AlertDismiss.js +11 -0
- package/dist/components/Attachment.d.ts +58 -0
- package/dist/components/Attachment.js +69 -0
- package/dist/components/AttachmentParts.d.ts +24 -0
- package/dist/components/AttachmentParts.js +20 -0
- package/dist/components/Chart.d.ts +1 -0
- package/dist/components/Chart.js +6 -1
- package/dist/components/ChartCore.d.ts +6 -1
- package/dist/components/ChartCore.js +23 -5
- package/dist/components/Chip.d.ts +17 -2
- package/dist/components/Chip.js +35 -11
- package/dist/components/ChipRemove.d.ts +17 -0
- package/dist/components/ChipRemove.js +13 -0
- package/dist/components/CollapsibleParts.d.ts +29 -0
- package/dist/components/CollapsibleParts.js +20 -0
- package/dist/components/CollapsibleSection.d.ts +30 -3
- package/dist/components/CollapsibleSection.js +7 -11
- package/dist/components/CollapsibleSectionState.d.ts +1 -1
- package/dist/components/CollapsibleSectionState.js +54 -27
- package/dist/components/DashboardGrid.d.ts +60 -0
- package/dist/components/DashboardGrid.js +40 -0
- package/dist/components/DateRangePicker.d.ts +7 -1
- package/dist/components/DateRangePicker.js +5 -1
- package/dist/components/DescriptionList.d.ts +12 -1
- package/dist/components/DescriptionList.js +5 -5
- package/dist/components/Dialogs.d.ts +24 -3
- package/dist/components/Dialogs.js +74 -16
- package/dist/components/EntityPicker.d.ts +56 -0
- package/dist/components/EntityPicker.js +168 -0
- package/dist/components/FileIcon.d.ts +9 -0
- package/dist/components/FileIcon.js +17 -0
- package/dist/components/FileUpload.d.ts +95 -0
- package/dist/components/FileUpload.js +145 -0
- package/dist/components/FilterEditor.d.ts +55 -0
- package/dist/components/FilterEditor.js +186 -0
- package/dist/components/Heartbeat.d.ts +31 -0
- package/dist/components/Heartbeat.js +28 -0
- package/dist/components/Lightbox.d.ts +45 -0
- package/dist/components/Lightbox.js +102 -0
- package/dist/components/Menu.d.ts +53 -5
- package/dist/components/Menu.js +104 -4
- package/dist/components/Meter.d.ts +7 -3
- package/dist/components/Meter.js +2 -1
- package/dist/components/Popover.d.ts +21 -2
- package/dist/components/Popover.js +94 -17
- package/dist/components/Prose.d.ts +6 -2
- package/dist/components/Prose.js +1 -1
- package/dist/components/RuleBuilder.d.ts +52 -4
- package/dist/components/RuleBuilder.js +109 -24
- package/dist/components/SchedulingCalendar.d.ts +142 -11
- package/dist/components/SchedulingCalendar.js +234 -57
- package/dist/components/SchedulingTimeline.d.ts +1 -0
- package/dist/components/SearchSuggest.d.ts +6 -2
- package/dist/components/SearchSuggest.js +4 -0
- package/dist/components/Segmented.d.ts +17 -3
- package/dist/components/Segmented.js +59 -5
- package/dist/components/Select.d.ts +66 -2
- package/dist/components/Select.js +800 -10
- package/dist/components/Spinner.d.ts +2 -1
- package/dist/components/Spinner.js +1 -1
- package/dist/components/StatusPill.d.ts +8 -2
- package/dist/components/StatusPill.js +2 -2
- package/dist/components/Steps.d.ts +28 -4
- package/dist/components/Steps.js +46 -16
- package/dist/components/TableControls.js +4 -3
- package/dist/components/Tabs.d.ts +7 -2
- package/dist/components/Tabs.js +14 -1
- package/dist/components/TextDiff.d.ts +49 -0
- package/dist/components/TextDiff.js +124 -0
- package/dist/{emoji-image-6mPZ15Zy.d.cts → emoji-image-DjCKpdwE.d.cts} +1 -1
- package/dist/emoji.cjs +169 -27
- package/dist/emoji.d.cts +3 -3
- package/dist/file-model.d.ts +56 -0
- package/dist/file-model.js +52 -0
- package/dist/filter-model.d.ts +112 -0
- package/dist/filter-model.js +103 -0
- package/dist/hooks/useAnchoredPosition.d.ts +24 -1
- package/dist/hooks/useAnchoredPosition.js +58 -8
- package/dist/hooks/useVirtualRows.d.ts +17 -2
- package/dist/hooks/useVirtualRows.js +6 -5
- package/dist/icons/Icon.d.ts +14 -14
- package/dist/index.cjs +4938 -1631
- package/dist/index.d.cts +1622 -178
- package/dist/index.d.ts +20 -6
- package/dist/index.js +88 -4
- package/dist/labels-context.d.ts +28 -0
- package/dist/{overlay-position-Cjv5E7mn.d.cts → overlay-position-2Afke51l.d.cts} +20 -0
- package/dist/overlay-position.d.ts +20 -0
- package/dist/overlay-position.js +17 -2
- package/dist/rich-text.cjs +169 -27
- package/dist/rich-text.d.cts +3 -3
- package/dist/rule-builder-model.d.ts +34 -2
- package/dist/rule-builder-model.js +48 -12
- package/dist/scheduling-calendar-model.d.ts +66 -0
- package/dist/scheduling-calendar-model.js +82 -0
- package/dist/select-model.d.ts +80 -0
- package/dist/select-model.js +109 -0
- package/dist/table-engine.d.ts +7 -0
- package/dist/table-engine.js +2 -1
- package/dist/text-diff-model.d.ts +71 -0
- package/dist/text-diff-model.js +261 -0
- package/package.json +1 -1
- package/dist/ChartCore-DzWe10bN.d.cts +0 -59
|
@@ -3,13 +3,18 @@ import { ReactElement, ReactNode } from 'react';
|
|
|
3
3
|
import { UixRenderLink } from '../link.js';
|
|
4
4
|
import { Placement } from '../overlay-position.js';
|
|
5
5
|
|
|
6
|
+
/** `id` and `data-*` for the item's own element (HAR-1629): a stable hook for tests, journeys and analytics. */
|
|
7
|
+
interface MenuItemAttributes {
|
|
8
|
+
id?: string;
|
|
9
|
+
[dataAttribute: `data-${string}`]: string | number | boolean | undefined;
|
|
10
|
+
}
|
|
6
11
|
interface MenuProps {
|
|
7
12
|
/**
|
|
8
13
|
* The menu button, usually a `Button`. It receives `aria-haspopup="menu"`,
|
|
9
14
|
* `aria-expanded`, `aria-controls` and the open/keyboard handlers.
|
|
10
15
|
*/
|
|
11
16
|
trigger: ReactElement;
|
|
12
|
-
/** `MenuItem`, `MenuGroup` and `MenuSeparator`. */
|
|
17
|
+
/** `MenuItem`, `MenuItemRadio`, `MenuItemCheckbox`, `MenuRadioGroup`, `MenuGroup` and `MenuSeparator`. */
|
|
13
18
|
children?: ReactNode;
|
|
14
19
|
/** Controlled open state; pair with `onOpenChange`. */
|
|
15
20
|
open?: boolean;
|
|
@@ -23,10 +28,11 @@ interface MenuProps {
|
|
|
23
28
|
/**
|
|
24
29
|
* A menu button with an APG menu (HAR-1359; TENSOR C1, MOTUS B-A14): ↓/↑ move, Home/End,
|
|
25
30
|
* type-to-find, Enter/Space activate, Esc and Tab close, focus returns to the trigger.
|
|
26
|
-
* The surface is the kit `Popover`, so it escapes clipping containers
|
|
31
|
+
* The surface is the kit `Popover`, so it escapes clipping containers; a menu taller than
|
|
32
|
+
* the viewport is capped to it and scrolls (HAR-1613).
|
|
27
33
|
*/
|
|
28
34
|
declare function Menu({ trigger, children, open: controlledOpen, defaultOpen, onOpenChange, label, placement, className }: MenuProps): react.JSX.Element;
|
|
29
|
-
interface MenuItemProps {
|
|
35
|
+
interface MenuItemProps extends MenuItemAttributes {
|
|
30
36
|
children?: ReactNode;
|
|
31
37
|
/** Runs on click, Enter or Space; the menu then closes and focus returns to the trigger. */
|
|
32
38
|
onSelect?: () => void;
|
|
@@ -40,7 +46,49 @@ interface MenuItemProps {
|
|
|
40
46
|
disabled?: boolean;
|
|
41
47
|
className?: string;
|
|
42
48
|
}
|
|
43
|
-
declare function MenuItem({ children, onSelect, href, renderLink, icon, shortcut, tone, disabled, className }: MenuItemProps): react.JSX.Element;
|
|
49
|
+
declare function MenuItem({ children, onSelect, href, renderLink, icon, shortcut, tone, disabled, className, ...rest }: MenuItemProps): react.JSX.Element;
|
|
50
|
+
interface MenuRadioGroupProps {
|
|
51
|
+
/** The `value` of the checked `MenuItemRadio`. */
|
|
52
|
+
value?: string;
|
|
53
|
+
onValueChange?: (value: string) => void;
|
|
54
|
+
/** Visible group heading; it also names the group. */
|
|
55
|
+
label?: ReactNode;
|
|
56
|
+
/** Names the group when there is no visible `label`. */
|
|
57
|
+
'aria-label'?: string;
|
|
58
|
+
children?: ReactNode;
|
|
59
|
+
}
|
|
60
|
+
/** One choice out of several inside a `Menu`: wraps `MenuItemRadio` rows and holds their value (HAR-1629). */
|
|
61
|
+
declare function MenuRadioGroup({ value, onValueChange, label, 'aria-label': ariaLabel, children }: MenuRadioGroupProps): react.JSX.Element;
|
|
62
|
+
interface MenuItemRadioProps extends MenuItemAttributes {
|
|
63
|
+
/** Checked when it equals the surrounding `MenuRadioGroup`'s `value`. */
|
|
64
|
+
value: string;
|
|
65
|
+
/** For a radio item used without a `MenuRadioGroup`. */
|
|
66
|
+
checked?: boolean;
|
|
67
|
+
/** Runs when the item is chosen, after the group's `onValueChange`. */
|
|
68
|
+
onSelect?: () => void;
|
|
69
|
+
/** Close the menu after a click or Enter. Default `true`. Space never closes it. */
|
|
70
|
+
closeOnSelect?: boolean;
|
|
71
|
+
children?: ReactNode;
|
|
72
|
+
icon?: ReactNode;
|
|
73
|
+
shortcut?: ReactNode;
|
|
74
|
+
disabled?: boolean;
|
|
75
|
+
className?: string;
|
|
76
|
+
}
|
|
77
|
+
/** A `role="menuitemradio"` row with `aria-checked` and a check mark for the current choice. */
|
|
78
|
+
declare function MenuItemRadio({ value, checked, onSelect, closeOnSelect, ...rest }: MenuItemRadioProps): react.JSX.Element;
|
|
79
|
+
interface MenuItemCheckboxProps extends MenuItemAttributes {
|
|
80
|
+
checked: boolean;
|
|
81
|
+
onCheckedChange?: (checked: boolean) => void;
|
|
82
|
+
/** Close the menu after a click or Enter. Default `false`: several boxes are usually ticked in a row. */
|
|
83
|
+
closeOnSelect?: boolean;
|
|
84
|
+
children?: ReactNode;
|
|
85
|
+
icon?: ReactNode;
|
|
86
|
+
shortcut?: ReactNode;
|
|
87
|
+
disabled?: boolean;
|
|
88
|
+
className?: string;
|
|
89
|
+
}
|
|
90
|
+
/** A `role="menuitemcheckbox"` row with `aria-checked`; the menu stays open while boxes are ticked. */
|
|
91
|
+
declare function MenuItemCheckbox({ checked, onCheckedChange, closeOnSelect, ...rest }: MenuItemCheckboxProps): react.JSX.Element;
|
|
44
92
|
interface MenuGroupProps {
|
|
45
93
|
label: ReactNode;
|
|
46
94
|
children?: ReactNode;
|
|
@@ -48,4 +96,4 @@ interface MenuGroupProps {
|
|
|
48
96
|
declare function MenuGroup({ label, children }: MenuGroupProps): react.JSX.Element;
|
|
49
97
|
declare function MenuSeparator(): react.JSX.Element;
|
|
50
98
|
|
|
51
|
-
export { Menu, MenuGroup, type MenuGroupProps, MenuItem, type MenuItemProps, type MenuProps, MenuSeparator };
|
|
99
|
+
export { Menu, MenuGroup, type MenuGroupProps, MenuItem, type MenuItemAttributes, MenuItemCheckbox, type MenuItemCheckboxProps, type MenuItemProps, MenuItemRadio, type MenuItemRadioProps, type MenuProps, MenuRadioGroup, type MenuRadioGroupProps, MenuSeparator };
|
package/dist/components/Menu.js
CHANGED
|
@@ -3,9 +3,16 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { cloneElement, createContext, isValidElement, useContext, useEffect, useId, useRef, useState } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
5
|
import { Popover } from "./Popover.js";
|
|
6
|
+
import { CheckIcon } from "../icons/components.js";
|
|
6
7
|
import { renderUixLink } from "../link.js";
|
|
7
8
|
const MenuContext = createContext(null);
|
|
8
|
-
const
|
|
9
|
+
const MenuRadioContext = createContext(null);
|
|
10
|
+
const ITEM = '[role^="menuitem"]:not([aria-disabled="true"])';
|
|
11
|
+
const itemAttributes = (rest) => {
|
|
12
|
+
const out = {};
|
|
13
|
+
for (const key of Object.keys(rest)) if (key === "id" || key.startsWith("data-")) out[key] = rest[key];
|
|
14
|
+
return out;
|
|
15
|
+
};
|
|
9
16
|
function Menu({ trigger, children, open: controlledOpen, defaultOpen = false, onOpenChange, label, placement = "bottom-start", className }) {
|
|
10
17
|
const id = useId();
|
|
11
18
|
const menuId = `${id}-menu`;
|
|
@@ -51,7 +58,8 @@ function Menu({ trigger, children, open: controlledOpen, defaultOpen = false, on
|
|
|
51
58
|
}
|
|
52
59
|
}
|
|
53
60
|
const list = items();
|
|
54
|
-
|
|
61
|
+
const start = focusOnOpen.current === "last" ? list[list.length - 1] : list.find((item) => item.getAttribute("role") === "menuitemradio" && item.getAttribute("aria-checked") === "true") ?? list[0];
|
|
62
|
+
start?.focus();
|
|
55
63
|
const onPointer = (event) => {
|
|
56
64
|
const target = event.target;
|
|
57
65
|
if (el.contains(target) || triggerRef.current?.contains(target)) return;
|
|
@@ -109,6 +117,12 @@ function Menu({ trigger, children, open: controlledOpen, defaultOpen = false, on
|
|
|
109
117
|
const list = items();
|
|
110
118
|
(focusOnOpen.current === "last" ? list[list.length - 1] : list[0])?.focus();
|
|
111
119
|
} else setOpen(true);
|
|
120
|
+
} else if (open && event.key === "Escape") {
|
|
121
|
+
event.preventDefault();
|
|
122
|
+
event.stopPropagation();
|
|
123
|
+
close(true);
|
|
124
|
+
} else if (open && event.key === "Tab") {
|
|
125
|
+
close(false);
|
|
112
126
|
}
|
|
113
127
|
}
|
|
114
128
|
}) : trigger;
|
|
@@ -121,6 +135,7 @@ function Menu({ trigger, children, open: controlledOpen, defaultOpen = false, on
|
|
|
121
135
|
popover: "manual",
|
|
122
136
|
anchor: triggerRef,
|
|
123
137
|
placement,
|
|
138
|
+
capHeight: true,
|
|
124
139
|
role: "menu",
|
|
125
140
|
"aria-label": label,
|
|
126
141
|
"aria-labelledby": label ? void 0 : triggerProps.id ?? triggerId,
|
|
@@ -131,20 +146,22 @@ function Menu({ trigger, children, open: controlledOpen, defaultOpen = false, on
|
|
|
131
146
|
)
|
|
132
147
|
] });
|
|
133
148
|
}
|
|
134
|
-
function MenuItem({ children, onSelect, href, renderLink, icon, shortcut, tone = "default", disabled, className }) {
|
|
149
|
+
function MenuItem({ children, onSelect, href, renderLink, icon, shortcut, tone = "default", disabled, className, ...rest }) {
|
|
135
150
|
const menu = useContext(MenuContext);
|
|
136
151
|
const classes = cx("uix-menu__item", tone === "danger" && "uix-menu__item--danger", className);
|
|
152
|
+
const attributes = itemAttributes(rest);
|
|
137
153
|
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
138
154
|
icon != null && /* @__PURE__ */ jsx("span", { className: "uix-menu__icon", "aria-hidden": "true", children: icon }),
|
|
139
155
|
/* @__PURE__ */ jsx("span", { className: "uix-menu__text", children }),
|
|
140
156
|
shortcut != null && /* @__PURE__ */ jsx("span", { className: "uix-menu__shortcut", children: shortcut })
|
|
141
157
|
] });
|
|
142
158
|
if (href != null && !disabled) {
|
|
143
|
-
return /* @__PURE__ */ jsx(Fragment, { children: renderUixLink(renderLink, { href, role: "menuitem", tabIndex: -1, className: classes, onClick: () => menu?.close(false), children: body }) });
|
|
159
|
+
return /* @__PURE__ */ jsx(Fragment, { children: renderUixLink(renderLink, { ...attributes, href, role: "menuitem", tabIndex: -1, className: classes, onClick: () => menu?.close(false), children: body }) });
|
|
144
160
|
}
|
|
145
161
|
return /* @__PURE__ */ jsx(
|
|
146
162
|
"button",
|
|
147
163
|
{
|
|
164
|
+
...attributes,
|
|
148
165
|
type: "button",
|
|
149
166
|
role: "menuitem",
|
|
150
167
|
tabIndex: -1,
|
|
@@ -159,6 +176,86 @@ function MenuItem({ children, onSelect, href, renderLink, icon, shortcut, tone =
|
|
|
159
176
|
}
|
|
160
177
|
);
|
|
161
178
|
}
|
|
179
|
+
function CheckableItem({
|
|
180
|
+
role,
|
|
181
|
+
checked,
|
|
182
|
+
onToggle,
|
|
183
|
+
closeOnSelect,
|
|
184
|
+
children,
|
|
185
|
+
icon,
|
|
186
|
+
shortcut,
|
|
187
|
+
disabled,
|
|
188
|
+
className,
|
|
189
|
+
...rest
|
|
190
|
+
}) {
|
|
191
|
+
const menu = useContext(MenuContext);
|
|
192
|
+
return /* @__PURE__ */ jsxs(
|
|
193
|
+
"button",
|
|
194
|
+
{
|
|
195
|
+
...itemAttributes(rest),
|
|
196
|
+
type: "button",
|
|
197
|
+
role,
|
|
198
|
+
"aria-checked": checked,
|
|
199
|
+
tabIndex: -1,
|
|
200
|
+
className: cx("uix-menu__item", className),
|
|
201
|
+
"aria-disabled": disabled || void 0,
|
|
202
|
+
onKeyDown: (event) => {
|
|
203
|
+
if (event.key !== " " || disabled) return;
|
|
204
|
+
event.preventDefault();
|
|
205
|
+
onToggle();
|
|
206
|
+
},
|
|
207
|
+
onKeyUp: (event) => {
|
|
208
|
+
if (event.key === " ") event.preventDefault();
|
|
209
|
+
},
|
|
210
|
+
onClick: () => {
|
|
211
|
+
if (disabled) return;
|
|
212
|
+
onToggle();
|
|
213
|
+
if (closeOnSelect) menu?.close(true);
|
|
214
|
+
},
|
|
215
|
+
children: [
|
|
216
|
+
/* @__PURE__ */ jsx("span", { className: "uix-menu__check", "aria-hidden": "true", children: checked && /* @__PURE__ */ jsx(CheckIcon, {}) }),
|
|
217
|
+
icon != null && /* @__PURE__ */ jsx("span", { className: "uix-menu__icon", "aria-hidden": "true", children: icon }),
|
|
218
|
+
/* @__PURE__ */ jsx("span", { className: "uix-menu__text", children }),
|
|
219
|
+
shortcut != null && /* @__PURE__ */ jsx("span", { className: "uix-menu__shortcut", children: shortcut })
|
|
220
|
+
]
|
|
221
|
+
}
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
function MenuRadioGroup({ value, onValueChange, label, "aria-label": ariaLabel, children }) {
|
|
225
|
+
const id = useId();
|
|
226
|
+
return /* @__PURE__ */ jsx(MenuRadioContext.Provider, { value: { value, onValueChange }, children: /* @__PURE__ */ jsxs("div", { role: "group", "aria-labelledby": label != null ? id : void 0, "aria-label": label != null ? void 0 : ariaLabel, children: [
|
|
227
|
+
label != null && /* @__PURE__ */ jsx("div", { id, className: "uix-menu__label", children: label }),
|
|
228
|
+
children
|
|
229
|
+
] }) });
|
|
230
|
+
}
|
|
231
|
+
function MenuItemRadio({ value, checked, onSelect, closeOnSelect = true, ...rest }) {
|
|
232
|
+
const group = useContext(MenuRadioContext);
|
|
233
|
+
return /* @__PURE__ */ jsx(
|
|
234
|
+
CheckableItem,
|
|
235
|
+
{
|
|
236
|
+
...rest,
|
|
237
|
+
role: "menuitemradio",
|
|
238
|
+
checked: checked ?? (group != null && group.value === value),
|
|
239
|
+
closeOnSelect,
|
|
240
|
+
onToggle: () => {
|
|
241
|
+
group?.onValueChange?.(value);
|
|
242
|
+
onSelect?.();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
function MenuItemCheckbox({ checked, onCheckedChange, closeOnSelect = false, ...rest }) {
|
|
248
|
+
return /* @__PURE__ */ jsx(
|
|
249
|
+
CheckableItem,
|
|
250
|
+
{
|
|
251
|
+
...rest,
|
|
252
|
+
role: "menuitemcheckbox",
|
|
253
|
+
checked,
|
|
254
|
+
closeOnSelect,
|
|
255
|
+
onToggle: () => onCheckedChange?.(!checked)
|
|
256
|
+
}
|
|
257
|
+
);
|
|
258
|
+
}
|
|
162
259
|
function MenuGroup({ label, children }) {
|
|
163
260
|
const id = useId();
|
|
164
261
|
return /* @__PURE__ */ jsxs("div", { role: "group", "aria-labelledby": id, children: [
|
|
@@ -173,5 +270,8 @@ export {
|
|
|
173
270
|
Menu,
|
|
174
271
|
MenuGroup,
|
|
175
272
|
MenuItem,
|
|
273
|
+
MenuItemCheckbox,
|
|
274
|
+
MenuItemRadio,
|
|
275
|
+
MenuRadioGroup,
|
|
176
276
|
MenuSeparator
|
|
177
277
|
};
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { HTMLAttributes } from 'react';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Fill color tone for the meter bar. Defaults to `success` (green).
|
|
6
|
+
* `neutral` and `accent` are for a plain proportion that is neither good nor bad (a poll
|
|
7
|
+
* option's share of the votes): a grey or brand fill, and no tone word is spoken (HAR-1606).
|
|
8
|
+
*/
|
|
9
|
+
type MeterTone = 'success' | 'warning' | 'danger' | 'attention' | 'overdue' | 'neutral' | 'accent';
|
|
6
10
|
interface MeterProps extends HTMLAttributes<HTMLDivElement> {
|
|
7
11
|
/** Fill level 0–100. Clamped to this range. */
|
|
8
12
|
value?: number;
|
|
@@ -11,7 +15,7 @@ interface MeterProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
11
15
|
/** Accessible name — rendered as `aria-label` (an explicit `aria-label` prop wins). */
|
|
12
16
|
label?: string;
|
|
13
17
|
/** TENSOR RX-125 (UIX-04): the spoken tone words; English defaults. */
|
|
14
|
-
toneLabels?: Partial<Record<Exclude<MeterTone, 'success'>, string>>;
|
|
18
|
+
toneLabels?: Partial<Record<Exclude<MeterTone, 'success' | 'neutral' | 'accent'>, string>>;
|
|
15
19
|
}
|
|
16
20
|
/** Horizontal utilization / threshold bar backed by `.uix-meter`. */
|
|
17
21
|
declare function Meter({ value, tone, label, toneLabels, className, ...props }: MeterProps): react.JSX.Element;
|
package/dist/components/Meter.js
CHANGED
|
@@ -9,6 +9,7 @@ const toneText = {
|
|
|
9
9
|
function Meter({ value = 0, tone, label, toneLabels, className, ...props }) {
|
|
10
10
|
const spoken = { ...toneText, ...toneLabels };
|
|
11
11
|
const pct = Math.max(0, Math.min(100, value));
|
|
12
|
+
const toneWord = tone ? spoken[tone] : void 0;
|
|
12
13
|
return /* @__PURE__ */ jsx(
|
|
13
14
|
"div",
|
|
14
15
|
{
|
|
@@ -16,7 +17,7 @@ function Meter({ value = 0, tone, label, toneLabels, className, ...props }) {
|
|
|
16
17
|
"aria-valuenow": pct,
|
|
17
18
|
"aria-valuemin": 0,
|
|
18
19
|
"aria-valuemax": 100,
|
|
19
|
-
"aria-valuetext":
|
|
20
|
+
"aria-valuetext": toneWord ? `${pct}%, ${toneWord}` : void 0,
|
|
20
21
|
"aria-label": label,
|
|
21
22
|
className: cx("uix-meter", className),
|
|
22
23
|
...props,
|
|
@@ -10,7 +10,8 @@ interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
10
10
|
popover?: 'auto' | 'manual';
|
|
11
11
|
/**
|
|
12
12
|
* Element (or ref) to anchor against. When set, the popover is placed with
|
|
13
|
-
* cross-browser JS positioning — flip when it won't fit, shift to stay on-screen.
|
|
13
|
+
* cross-browser JS positioning — flip when it won't fit, shift to stay on-screen. A popover
|
|
14
|
+
* that fits neither above nor below slides over its anchor rather than leave the viewport.
|
|
14
15
|
* Where the browser supports CSS anchor positioning, the placement is written as an
|
|
15
16
|
* offset from the anchor, so it stays attached while the page scrolls; elsewhere it
|
|
16
17
|
* follows scroll from JS. The native Popover API still provides the top layer (so it
|
|
@@ -30,6 +31,24 @@ interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
30
31
|
closeWhenAnchorHidden?: boolean;
|
|
31
32
|
/** Called when `closeWhenAnchorHidden` is about to close the popover. */
|
|
32
33
|
onAnchorHidden?: () => void;
|
|
34
|
+
/**
|
|
35
|
+
* Cap the popover's height to the viewport (minus 8 px at each edge) and scroll inside it,
|
|
36
|
+
* for content that can be taller than a phone screen. Needs `anchor`. Default `false`.
|
|
37
|
+
*/
|
|
38
|
+
capHeight?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Open while the pointer is over the `anchor` or the anchor has keyboard focus, and close
|
|
41
|
+
* when both have left the anchor and the popover — a hover card (HAR-1614). The pointer can
|
|
42
|
+
* travel from the anchor into the popover, and focus can move into it, without closing it;
|
|
43
|
+
* Escape closes it. Touch does not hover: open it from the anchor's own click there.
|
|
44
|
+
* `true` waits 300 ms before opening and 150 ms before closing; pass the delays to change
|
|
45
|
+
* them. Needs `anchor`; `popover` then defaults to `"manual"`, so a hover card does not
|
|
46
|
+
* dismiss a menu or dialog that is open.
|
|
47
|
+
*/
|
|
48
|
+
openOnHover?: boolean | {
|
|
49
|
+
openDelay?: number;
|
|
50
|
+
closeDelay?: number;
|
|
51
|
+
};
|
|
33
52
|
children?: ReactNode;
|
|
34
53
|
}
|
|
35
54
|
/**
|
|
@@ -37,6 +56,6 @@ interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
37
56
|
* things like a filter popover, menu, or rich select by putting controls inside.
|
|
38
57
|
* Pass `anchor` to get collision-aware, cross-browser placement (UIX-FIX-02).
|
|
39
58
|
*/
|
|
40
|
-
declare function Popover({ popover, anchor, placement, offset, closeWhenAnchorHidden, onAnchorHidden, className, children, ...props }: PopoverProps): react.JSX.Element;
|
|
59
|
+
declare function Popover({ popover: popoverProp, anchor, placement, offset, closeWhenAnchorHidden, onAnchorHidden, capHeight, openOnHover, className, children, ...props }: PopoverProps): react.JSX.Element;
|
|
41
60
|
|
|
42
61
|
export { Popover, type PopoverProps };
|
|
@@ -18,16 +18,22 @@ const settle = (el) => {
|
|
|
18
18
|
el.removeAttribute(PLACING);
|
|
19
19
|
};
|
|
20
20
|
function Popover({
|
|
21
|
-
popover
|
|
21
|
+
popover: popoverProp,
|
|
22
22
|
anchor,
|
|
23
23
|
placement = "bottom-start",
|
|
24
24
|
offset = 6,
|
|
25
25
|
closeWhenAnchorHidden = false,
|
|
26
26
|
onAnchorHidden,
|
|
27
|
+
capHeight = false,
|
|
28
|
+
openOnHover = false,
|
|
27
29
|
className,
|
|
28
30
|
children,
|
|
29
31
|
...props
|
|
30
32
|
}) {
|
|
33
|
+
const hover = !!openOnHover && !!anchor;
|
|
34
|
+
const popover = popoverProp ?? (hover ? "manual" : "auto");
|
|
35
|
+
const openDelay = typeof openOnHover === "object" ? openOnHover.openDelay ?? 300 : 300;
|
|
36
|
+
const closeDelay = typeof openOnHover === "object" ? openOnHover.closeDelay ?? 150 : 150;
|
|
31
37
|
const ref = useRef(null);
|
|
32
38
|
const [open, setOpen] = useState(false);
|
|
33
39
|
const openRef = useRef(false);
|
|
@@ -37,7 +43,16 @@ function Popover({
|
|
|
37
43
|
const reposition = useAnchoredPosition(anchor ?? null, ref, {
|
|
38
44
|
open: open && !!anchor,
|
|
39
45
|
placement,
|
|
40
|
-
offset
|
|
46
|
+
offset,
|
|
47
|
+
capHeight,
|
|
48
|
+
onAnchorHidden: closeWhenAnchorHidden ? () => {
|
|
49
|
+
const el = ref.current;
|
|
50
|
+
if (!el || !isPopoverOpen(el)) return;
|
|
51
|
+
onAnchorHiddenRef.current?.();
|
|
52
|
+
const active = el.ownerDocument.activeElement;
|
|
53
|
+
if (active && el.contains(active)) active.blur();
|
|
54
|
+
el.hidePopover();
|
|
55
|
+
} : void 0
|
|
41
56
|
});
|
|
42
57
|
useEffect(() => {
|
|
43
58
|
const el = ref.current;
|
|
@@ -72,25 +87,87 @@ function Popover({
|
|
|
72
87
|
el.removeAttribute(PLACING);
|
|
73
88
|
};
|
|
74
89
|
}, [anchor, reposition]);
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
const el = ref.current;
|
|
92
|
+
const anchorEl = resolveAnchor(anchor);
|
|
93
|
+
if (!hover || !el || !anchorEl) return;
|
|
94
|
+
let timer;
|
|
95
|
+
const inside = (node) => !!node && (anchorEl.contains(node) || el.contains(node));
|
|
96
|
+
const stillWanted = () => {
|
|
97
|
+
try {
|
|
98
|
+
return anchorEl.matches(":hover") || el.matches(":hover") || inside(el.ownerDocument.activeElement);
|
|
99
|
+
} catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
const show = (delay) => {
|
|
104
|
+
window.clearTimeout(timer);
|
|
105
|
+
timer = window.setTimeout(() => {
|
|
106
|
+
if (!isPopoverOpen(el)) {
|
|
107
|
+
try {
|
|
108
|
+
el.showPopover?.();
|
|
109
|
+
} catch {
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}, delay);
|
|
113
|
+
};
|
|
114
|
+
const hide = (delay) => {
|
|
115
|
+
window.clearTimeout(timer);
|
|
116
|
+
timer = window.setTimeout(() => {
|
|
117
|
+
if (isPopoverOpen(el) && !stillWanted()) {
|
|
118
|
+
try {
|
|
119
|
+
el.hidePopover?.();
|
|
120
|
+
} catch {
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}, delay);
|
|
124
|
+
};
|
|
125
|
+
const onEnter = (event) => {
|
|
126
|
+
if (event.pointerType !== "touch") show(openDelay);
|
|
127
|
+
};
|
|
128
|
+
const onLeave = (event) => {
|
|
129
|
+
if (event.pointerType !== "touch") hide(closeDelay);
|
|
130
|
+
};
|
|
131
|
+
const onFocusIn = () => show(0);
|
|
132
|
+
const onFocusOut = (event) => {
|
|
133
|
+
if (!inside(event.relatedTarget)) hide(closeDelay);
|
|
134
|
+
};
|
|
135
|
+
const onKeyDown = (event) => {
|
|
136
|
+
if (event.key !== "Escape" || !isPopoverOpen(el)) return;
|
|
137
|
+
window.clearTimeout(timer);
|
|
138
|
+
const hadFocus = el.contains(el.ownerDocument.activeElement);
|
|
139
|
+
try {
|
|
140
|
+
el.hidePopover?.();
|
|
141
|
+
} catch {
|
|
142
|
+
}
|
|
143
|
+
if (hadFocus) {
|
|
144
|
+
anchorEl.removeEventListener("focusin", onFocusIn);
|
|
145
|
+
anchorEl.focus();
|
|
146
|
+
anchorEl.addEventListener("focusin", onFocusIn);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
for (const node of [anchorEl, el]) {
|
|
150
|
+
node.addEventListener("pointerenter", onEnter);
|
|
151
|
+
node.addEventListener("pointerleave", onLeave);
|
|
152
|
+
node.addEventListener("focusout", onFocusOut);
|
|
153
|
+
node.addEventListener("keydown", onKeyDown);
|
|
154
|
+
}
|
|
155
|
+
anchorEl.addEventListener("focusin", onFocusIn);
|
|
156
|
+
return () => {
|
|
157
|
+
window.clearTimeout(timer);
|
|
158
|
+
for (const node of [anchorEl, el]) {
|
|
159
|
+
node.removeEventListener("pointerenter", onEnter);
|
|
160
|
+
node.removeEventListener("pointerleave", onLeave);
|
|
161
|
+
node.removeEventListener("focusout", onFocusOut);
|
|
162
|
+
node.removeEventListener("keydown", onKeyDown);
|
|
163
|
+
}
|
|
164
|
+
anchorEl.removeEventListener("focusin", onFocusIn);
|
|
165
|
+
};
|
|
166
|
+
}, [hover, anchor, openDelay, closeDelay]);
|
|
75
167
|
useIsomorphicLayoutEffect(() => {
|
|
76
168
|
openRef.current = open;
|
|
77
169
|
if (open && ref.current) settle(ref.current);
|
|
78
170
|
}, [open]);
|
|
79
|
-
useEffect(() => {
|
|
80
|
-
const el = ref.current;
|
|
81
|
-
const anchorEl = resolveAnchor(anchor);
|
|
82
|
-
if (!closeWhenAnchorHidden || !open || !el || !anchorEl || typeof IntersectionObserver !== "function") return;
|
|
83
|
-
const observer = new IntersectionObserver((entries) => {
|
|
84
|
-
const latest = entries[entries.length - 1];
|
|
85
|
-
if (!latest || latest.isIntersecting || !isPopoverOpen(el)) return;
|
|
86
|
-
onAnchorHiddenRef.current?.();
|
|
87
|
-
const active = el.ownerDocument.activeElement;
|
|
88
|
-
if (active && el.contains(active)) active.blur();
|
|
89
|
-
el.hidePopover();
|
|
90
|
-
});
|
|
91
|
-
observer.observe(anchorEl);
|
|
92
|
-
return () => observer.disconnect();
|
|
93
|
-
}, [closeWhenAnchorHidden, open, anchor]);
|
|
94
171
|
return /* @__PURE__ */ jsx("div", { ref, className: cx("uix-popover", className), ...popoverAttr, ...props, children });
|
|
95
172
|
}
|
|
96
173
|
export {
|
|
@@ -9,9 +9,13 @@ interface ProseProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
9
9
|
* release notes). Apply to a block of rendered HTML/markdown.
|
|
10
10
|
*/
|
|
11
11
|
declare function Prose({ children, className, ...props }: ProseProps): react.JSX.Element;
|
|
12
|
-
type NoteTone = 'info' | 'success' | 'warning' | 'danger';
|
|
12
|
+
type NoteTone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';
|
|
13
13
|
interface NoteProps extends HTMLAttributes<HTMLDivElement> {
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* `'neutral'` and `undefined` are both the default look. `undefined` is spelled out in the type
|
|
16
|
+
* so `tone={maybeTone}` also compiles under `exactOptionalPropertyTypes` (HAR-1614).
|
|
17
|
+
*/
|
|
18
|
+
tone?: NoteTone | undefined;
|
|
15
19
|
icon?: ReactNode;
|
|
16
20
|
children?: ReactNode;
|
|
17
21
|
}
|
package/dist/components/Prose.js
CHANGED
|
@@ -4,7 +4,7 @@ function Prose({ children, className, ...props }) {
|
|
|
4
4
|
return /* @__PURE__ */ jsx("div", { className: cx("uix-prose", className), ...props, children });
|
|
5
5
|
}
|
|
6
6
|
function Note({ tone, icon, children, className, ...props }) {
|
|
7
|
-
return /* @__PURE__ */ jsxs("div", { className: cx("uix-note", tone && `uix-note--${tone}`, className), ...props, children: [
|
|
7
|
+
return /* @__PURE__ */ jsxs("div", { className: cx("uix-note", tone && tone !== "neutral" && `uix-note--${tone}`, className), ...props, children: [
|
|
8
8
|
icon != null && /* @__PURE__ */ jsx("div", { className: "uix-note__icon", children: icon }),
|
|
9
9
|
/* @__PURE__ */ jsx("div", { className: "uix-note__body", children })
|
|
10
10
|
] });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { JsonValue } from '../json-value.js';
|
|
4
|
-
import { RuleAction, RuleDefinition, RuleCondition, RuleValidationIssue } from '../rule-builder-model.js';
|
|
4
|
+
import { RuleAction, RuleDefinition, RuleCondition, RuleCheck, RuleValidationIssue } from '../rule-builder-model.js';
|
|
5
5
|
|
|
6
6
|
interface RuleValueEditorProps {
|
|
7
7
|
condition: RuleCondition;
|
|
@@ -28,6 +28,10 @@ interface RuleActionDefinition {
|
|
|
28
28
|
/**
|
|
29
29
|
* Every word the rule builder renders (TENSOR RX-125, UIX-12). `{item}` is one of
|
|
30
30
|
* `itemGroup` / `itemCondition` / `itemAction`; `{field}` a field label; `{count}` a number.
|
|
31
|
+
* The `issue…` keys are the built-in validation messages (`{id}` the duplicated id, `{max}`
|
|
32
|
+
* the depth limit) and the `summary…` / `and` / `or` keys the words of the
|
|
33
|
+
* `readOnly="summary"` sentence (HAR-1618). Translate once for a subtree with
|
|
34
|
+
* `UixLabelsProvider labels={{ ruleBuilder: … }}`.
|
|
31
35
|
*/
|
|
32
36
|
interface RuleBuilderLabels {
|
|
33
37
|
region: string;
|
|
@@ -59,6 +63,19 @@ interface RuleBuilderLabels {
|
|
|
59
63
|
addCondition: string;
|
|
60
64
|
addGroup: string;
|
|
61
65
|
addAction: string;
|
|
66
|
+
issueDuplicateId: string;
|
|
67
|
+
issueMaxDepth: string;
|
|
68
|
+
issueEmptyGroup: string;
|
|
69
|
+
issueMissingField: string;
|
|
70
|
+
issueMissingOperator: string;
|
|
71
|
+
issueNoActions: string;
|
|
72
|
+
issueMissingActionType: string;
|
|
73
|
+
summarySentence: string;
|
|
74
|
+
summarySentenceConditionsOnly: string;
|
|
75
|
+
summaryNoConditions: string;
|
|
76
|
+
summaryNoActions: string;
|
|
77
|
+
and: string;
|
|
78
|
+
or: string;
|
|
62
79
|
}
|
|
63
80
|
declare const DEFAULT_RULE_BUILDER_LABELS: RuleBuilderLabels;
|
|
64
81
|
interface RuleBuilderProps {
|
|
@@ -66,9 +83,40 @@ interface RuleBuilderProps {
|
|
|
66
83
|
onChange: (value: RuleDefinition) => void;
|
|
67
84
|
fields: RuleFieldDefinition[];
|
|
68
85
|
operators: RuleOperatorDefinition[];
|
|
69
|
-
|
|
86
|
+
/** The action types of the "Then" block. Not needed with `conditionsOnly`. */
|
|
87
|
+
actions?: RuleActionDefinition[];
|
|
70
88
|
maxDepth?: number;
|
|
71
|
-
|
|
89
|
+
/**
|
|
90
|
+
* `true`: the same builder with every control disabled and no add, move or remove buttons.
|
|
91
|
+
* `'summary'`: one sentence instead of the controls (what `readOnly` rendered up to 2.31.0;
|
|
92
|
+
* its words are the `summary…`, `and` and `or` labels).
|
|
93
|
+
*/
|
|
94
|
+
readOnly?: boolean | 'summary';
|
|
95
|
+
/**
|
|
96
|
+
* Edit conditions only (HAR-1618): no "Then" block and no "Add action", and the two action
|
|
97
|
+
* checks (`noActions`, `missingActionType`) are off. `value.then` is passed through untouched.
|
|
98
|
+
*/
|
|
99
|
+
conditionsOnly?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Fix every group to this combinator, for a stored shape that is a flat AND-list. The Match
|
|
102
|
+
* choice becomes plain text ("Match all (AND)"), new groups get this combinator, and every
|
|
103
|
+
* `onChange` carries it on all groups, so the other value is never emitted.
|
|
104
|
+
*/
|
|
105
|
+
combinator?: 'and' | 'or';
|
|
106
|
+
/** Hide the Match control (and its text when `combinator` fixes it). */
|
|
107
|
+
hideCombinator?: boolean;
|
|
108
|
+
/**
|
|
109
|
+
* `false` hides "Add group". It is hidden as well when `maxDepth` is 1, where it could never
|
|
110
|
+
* be used. Default `true`.
|
|
111
|
+
*/
|
|
112
|
+
allowGroups?: boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Turn built-in checks off: `{ emptyGroup: false }` for a rule that may have no condition
|
|
115
|
+
* (a catch-all), `{ noActions: false }` for a rule that may do nothing. Their messages are
|
|
116
|
+
* the `issue…` labels.
|
|
117
|
+
*/
|
|
118
|
+
checks?: Partial<Record<RuleCheck, boolean>>;
|
|
119
|
+
/** Extra issues; they are appended to the built-in ones. */
|
|
72
120
|
validate?: (value: RuleDefinition) => RuleValidationIssue[];
|
|
73
121
|
className?: string;
|
|
74
122
|
/** @deprecated use `labels.addCondition` */
|
|
@@ -80,6 +128,6 @@ interface RuleBuilderProps {
|
|
|
80
128
|
labels?: Partial<RuleBuilderLabels>;
|
|
81
129
|
}
|
|
82
130
|
/** Declarative controlled when-conditions-to-actions editor with bounded nesting. */
|
|
83
|
-
declare function RuleBuilder({ value, onChange, fields, operators, actions, maxDepth, readOnly, validate, className, addConditionLabel, addGroupLabel, addActionLabel, labels: labelOverrides, }: RuleBuilderProps): react.JSX.Element;
|
|
131
|
+
declare function RuleBuilder({ value, onChange, fields, operators, actions, maxDepth, readOnly, conditionsOnly, combinator, hideCombinator, allowGroups, checks, validate, className, addConditionLabel, addGroupLabel, addActionLabel, labels: labelOverrides, }: RuleBuilderProps): react.JSX.Element;
|
|
84
132
|
|
|
85
133
|
export { DEFAULT_RULE_BUILDER_LABELS, type RuleActionDefinition, RuleBuilder, type RuleBuilderLabels, type RuleBuilderProps, type RuleFieldDefinition, type RuleOperatorDefinition, type RuleValueEditorProps };
|