@vuu-ui/vuu-table-extras 3.5.15 → 3.5.17

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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.5.15",
2
+ "version": "3.5.17",
3
3
  "author": "heswell",
4
4
  "main": "./src/index.js",
5
5
  "license": "Apache-2.0",
@@ -11,19 +11,19 @@
11
11
  "lezer-generate:column": "lezer-generator --output ./src/column-expression-input/column-language-parser/generated/column-parser.js ./src/column-expression-input/column-language-parser/grammar/column.grammar"
12
12
  },
13
13
  "devDependencies": {
14
- "@vuu-ui/vuu-filter-types": "3.5.15",
15
- "@vuu-ui/vuu-protocol-types": "3.5.15"
14
+ "@vuu-ui/vuu-filter-types": "3.5.17",
15
+ "@vuu-ui/vuu-protocol-types": "3.5.17"
16
16
  },
17
17
  "dependencies": {
18
- "@vuu-ui/vuu-codemirror": "3.5.15",
19
- "@vuu-ui/vuu-data-editing": "3.5.15",
20
- "@vuu-ui/vuu-data-react": "3.5.15",
21
- "@vuu-ui/vuu-data-types": "3.5.15",
22
- "@vuu-ui/vuu-table-types": "3.5.15",
23
- "@vuu-ui/vuu-popups": "3.5.15",
24
- "@vuu-ui/vuu-table": "3.5.15",
25
- "@vuu-ui/vuu-utils": "3.5.15",
26
- "@vuu-ui/vuu-ui-controls": "3.5.15",
18
+ "@vuu-ui/vuu-codemirror": "3.5.17",
19
+ "@vuu-ui/vuu-data-editing": "3.5.17",
20
+ "@vuu-ui/vuu-data-react": "3.5.17",
21
+ "@vuu-ui/vuu-data-types": "3.5.17",
22
+ "@vuu-ui/vuu-table-types": "3.5.17",
23
+ "@vuu-ui/vuu-popups": "3.5.17",
24
+ "@vuu-ui/vuu-table": "3.5.17",
25
+ "@vuu-ui/vuu-utils": "3.5.17",
26
+ "@vuu-ui/vuu-ui-controls": "3.5.17",
27
27
  "@lezer/lr": "1.4.2",
28
28
  "@salt-ds/core": "1.54.1",
29
29
  "@salt-ds/lab": "1.0.0-alpha.83",
@@ -38,22 +38,103 @@ const css = `
38
38
  background-color: #0000;
39
39
  }
40
40
 
41
- .vuuBackgroundCell-backgroundOnly.up1, .vuuBackgroundCell-arrowBackground.up1 {
41
+ .vuuBackgroundCell-backgroundOnly.vuuBackgroundCell-hotUp, .vuuBackgroundCell-arrowBackground.vuuBackgroundCell-hotUp {
42
+ background-color: var(--vuuBackgroundCell-hotUp-background, color-mix(in srgb, var(--salt-sentiment-positive-foreground-informative) 30%, transparent));
43
+ }
44
+
45
+ .vuuBackgroundCell-backgroundOnly.vuuBackgroundCell-hotDown, .vuuBackgroundCell-arrowBackground.vuuBackgroundCell-hotDown {
46
+ background-color: var(--vuuBackgroundCell-hotDown-background, color-mix(in srgb, var(--salt-sentiment-negative-foreground-informative) 30%, transparent));
47
+ }
48
+
49
+ .vuuBackgroundCell-backgroundOnly.vuuBackgroundCell-coolUp > .vuuBackgroundCell-flash {
50
+ background-color: var(--vuuBackgroundCell-hotUp-background, color-mix(in srgb, var(--salt-sentiment-positive-foreground-informative) 30%, transparent));
51
+ animation: vuucoolup var(--vuuBackgroundCell-cool-duration, 2s);
52
+ }
53
+
54
+ .vuuBackgroundCell-backgroundOnly.vuuBackgroundCell-coolDown > .vuuBackgroundCell-flash {
55
+ background-color: var(--vuuBackgroundCell-hotDown-background, color-mix(in srgb, var(--salt-sentiment-negative-foreground-informative) 30%, transparent));
56
+ animation: vuucooldown var(--vuuBackgroundCell-cool-duration, 2s);
57
+ }
58
+
59
+ .vuuBackgroundCell-arrowBackground.vuuBackgroundCell-coolUp {
60
+ animation: vuucoolbgup var(--vuuBackgroundCell-cool-duration, 2s);
61
+ }
62
+
63
+ .vuuBackgroundCell-arrowBackground.vuuBackgroundCell-coolDown {
64
+ animation: vuucoolbgdown var(--vuuBackgroundCell-cool-duration, 2s);
65
+ }
66
+
67
+ .vuuBackgroundCell-hotUp > .vuuBackgroundCell-arrow {
68
+ color: var(--salt-sentiment-positive-foreground-informative);
69
+ }
70
+
71
+ .vuuBackgroundCell-hotDown > .vuuBackgroundCell-arrow {
72
+ color: var(--salt-sentiment-negative-foreground-informative);
73
+ }
74
+
75
+ .vuuBackgroundCell-flash {
76
+ opacity: 0;
77
+ pointer-events: none;
78
+ position: absolute;
79
+ inset: 0;
80
+ }
81
+
82
+ .vuuBackgroundCell-backgroundOnly.up1 > .vuuBackgroundCell-flash, .vuuBackgroundCell-backgroundOnly.up2 > .vuuBackgroundCell-flash {
83
+ background-color: var(--salt-sentiment-positive-foreground-informative);
84
+ }
85
+
86
+ .vuuBackgroundCell-backgroundOnly.down1 > .vuuBackgroundCell-flash, .vuuBackgroundCell-backgroundOnly.down2 > .vuuBackgroundCell-flash {
87
+ background-color: var(--salt-sentiment-negative-foreground-informative);
88
+ }
89
+
90
+ .vuuBackgroundCell-backgroundOnly.up1 > .vuuBackgroundCell-flash {
91
+ animation: vuuflashup1 var(--background-animation-duration);
92
+ }
93
+
94
+ .vuuBackgroundCell-backgroundOnly.up2 > .vuuBackgroundCell-flash {
95
+ animation: vuuflashup2 var(--background-animation-duration);
96
+ }
97
+
98
+ .vuuBackgroundCell-backgroundOnly.down1 > .vuuBackgroundCell-flash {
99
+ animation: vuuflashdown1 var(--background-animation-duration);
100
+ }
101
+
102
+ .vuuBackgroundCell-backgroundOnly.down2 > .vuuBackgroundCell-flash {
103
+ animation: vuuflashdown2 var(--background-animation-duration);
104
+ }
105
+
106
+ .vuuBackgroundCell-backgroundOnly.up1 > .vuuBackgroundCell-value {
107
+ animation: vuuflashtextup1 var(--background-animation-duration);
108
+ }
109
+
110
+ .vuuBackgroundCell-backgroundOnly.up2 > .vuuBackgroundCell-value {
111
+ animation: vuuflashtextup2 var(--background-animation-duration);
112
+ }
113
+
114
+ .vuuBackgroundCell-backgroundOnly.down1 > .vuuBackgroundCell-value {
115
+ animation: vuuflashtextdown1 var(--background-animation-duration);
116
+ }
117
+
118
+ .vuuBackgroundCell-backgroundOnly.down2 > .vuuBackgroundCell-value {
119
+ animation: vuuflashtextdown2 var(--background-animation-duration);
120
+ }
121
+
122
+ .vuuBackgroundCell-arrowBackground.up1 {
42
123
  animation-duration: var(--background-animation-duration);
43
124
  animation-name: vuubgup1;
44
125
  }
45
126
 
46
- .vuuBackgroundCell-backgroundOnly.up2, .vuuBackgroundCell-arrowBackground.up2 {
127
+ .vuuBackgroundCell-arrowBackground.up2 {
47
128
  animation-duration: var(--background-animation-duration);
48
129
  animation-name: vuubgup2;
49
130
  }
50
131
 
51
- .vuuBackgroundCell-backgroundOnly.down1, .vuuBackgroundCell-arrowBackground.down1 {
132
+ .vuuBackgroundCell-arrowBackground.down1 {
52
133
  animation-duration: var(--background-animation-duration);
53
134
  animation-name: vuubgdown1;
54
135
  }
55
136
 
56
- .vuuBackgroundCell-backgroundOnly.down2, .vuuBackgroundCell-arrowBackground.down2 {
137
+ .vuuBackgroundCell-arrowBackground.down2 {
57
138
  animation-duration: var(--background-animation-duration);
58
139
  animation-name: vuubgdown2;
59
140
  }
@@ -36,25 +36,33 @@ const BackgroundCell_BackgroundCell = /*#__PURE__*/ memo(function({ column, data
36
36
  const { name, type, valueFormatter } = column;
37
37
  const value = dataRow[name];
38
38
  const flashStyle = getFlashStyle(type);
39
- const direction = useDirection(dataRow.key, value, column);
40
- const arrow = flashStyle === FlashStyle.ArrowOnly || flashStyle === FlashStyle.ArrowBackground ? direction === UP1 || direction === UP2 ? CHAR_ARROW_UP : direction === DOWN1 || direction === DOWN2 ? CHAR_ARROW_DOWN : null : null;
39
+ const { direction, hot, cooling } = useDirection(dataRow.key, value, column);
40
+ const arrow = flashStyle === FlashStyle.ArrowOnly || flashStyle === FlashStyle.ArrowBackground ? "up" === hot || direction === UP1 || direction === UP2 ? CHAR_ARROW_UP : "down" === hot || direction === DOWN1 || direction === DOWN2 ? CHAR_ARROW_DOWN : null : null;
41
41
  const dirClass = direction ? " " + direction : "";
42
42
  const className = clsx(classBase, dirClass, {
43
43
  [`${classBase}-backgroundOnly`]: flashStyle === FlashStyle.BackgroundOnly,
44
44
  [`${classBase}-arrowOnly`]: flashStyle === FlashStyle.ArrowOnly,
45
- [`${classBase}-arrowBackground`]: flashStyle === FlashStyle.ArrowBackground
45
+ [`${classBase}-arrowBackground`]: flashStyle === FlashStyle.ArrowBackground,
46
+ [`${classBase}-hotUp`]: "up" === hot,
47
+ [`${classBase}-hotDown`]: "down" === hot,
48
+ [`${classBase}-coolUp`]: "up" === cooling,
49
+ [`${classBase}-coolDown`]: "down" === cooling
46
50
  });
51
+ const formattedValue = valueFormatter(value);
47
52
  return /*#__PURE__*/ jsxs("div", {
48
53
  className: className,
49
54
  tabIndex: -1,
50
55
  children: [
51
- /*#__PURE__*/ jsx("div", {
56
+ flashStyle === FlashStyle.BackgroundOnly ? /*#__PURE__*/ jsx("span", {
57
+ "aria-hidden": true,
58
+ className: `${classBase}-flash`
59
+ }) : /*#__PURE__*/ jsx("div", {
52
60
  className: `${classBase}-arrow`,
53
61
  children: arrow
54
62
  }),
55
63
  /*#__PURE__*/ jsx("span", {
56
64
  className: `${classBase}-value`,
57
- children: valueFormatter(dataRow[name])
65
+ children: formattedValue
58
66
  })
59
67
  ]
60
68
  });
@@ -1,4 +1,128 @@
1
1
  const css = `
2
+ @keyframes vuucoolup {
3
+ from {
4
+ opacity: 1;
5
+ }
6
+
7
+ to {
8
+ opacity: 0;
9
+ }
10
+ }
11
+
12
+ @keyframes vuucooldown {
13
+ from {
14
+ opacity: 1;
15
+ }
16
+
17
+ to {
18
+ opacity: 0;
19
+ }
20
+ }
21
+
22
+ @keyframes vuucoolbgup {
23
+ from {
24
+ background-color: var(--vuuBackgroundCell-hotUp-background, color-mix(in srgb, var(--salt-sentiment-positive-foreground-informative) 30%, transparent));
25
+ }
26
+
27
+ to {
28
+ background-color: #0000;
29
+ }
30
+ }
31
+
32
+ @keyframes vuucoolbgdown {
33
+ from {
34
+ background-color: var(--vuuBackgroundCell-hotDown-background, color-mix(in srgb, var(--salt-sentiment-negative-foreground-informative) 30%, transparent));
35
+ }
36
+
37
+ to {
38
+ background-color: #0000;
39
+ }
40
+ }
41
+
42
+ @keyframes vuuflashtextup1 {
43
+ 0% {
44
+ color: var(--vuuBackgroundCell-flash-color, white);
45
+ animation-timing-function: step-end;
46
+ }
47
+
48
+ 33% {
49
+ color: var(--vuuBackgroundCell-color, var(--salt-content-primary-foreground));
50
+ }
51
+ }
52
+
53
+ @keyframes vuuflashtextup2 {
54
+ 0% {
55
+ color: var(--vuuBackgroundCell-flash-color, white);
56
+ animation-timing-function: step-end;
57
+ }
58
+
59
+ 33% {
60
+ color: var(--vuuBackgroundCell-color, var(--salt-content-primary-foreground));
61
+ }
62
+ }
63
+
64
+ @keyframes vuuflashtextdown1 {
65
+ 0% {
66
+ color: var(--vuuBackgroundCell-flash-color, white);
67
+ animation-timing-function: step-end;
68
+ }
69
+
70
+ 33% {
71
+ color: var(--vuuBackgroundCell-color, var(--salt-content-primary-foreground));
72
+ }
73
+ }
74
+
75
+ @keyframes vuuflashtextdown2 {
76
+ 0% {
77
+ color: var(--vuuBackgroundCell-flash-color, white);
78
+ animation-timing-function: step-end;
79
+ }
80
+
81
+ 33% {
82
+ color: var(--vuuBackgroundCell-color, var(--salt-content-primary-foreground));
83
+ }
84
+ }
85
+
86
+ @keyframes vuuflashup1 {
87
+ from {
88
+ opacity: 1;
89
+ }
90
+
91
+ to {
92
+ opacity: 0;
93
+ }
94
+ }
95
+
96
+ @keyframes vuuflashup2 {
97
+ from {
98
+ opacity: 1;
99
+ }
100
+
101
+ to {
102
+ opacity: 0;
103
+ }
104
+ }
105
+
106
+ @keyframes vuuflashdown1 {
107
+ from {
108
+ opacity: 1;
109
+ }
110
+
111
+ to {
112
+ opacity: 0;
113
+ }
114
+ }
115
+
116
+ @keyframes vuuflashdown2 {
117
+ from {
118
+ opacity: 1;
119
+ }
120
+
121
+ to {
122
+ opacity: 0;
123
+ }
124
+ }
125
+
2
126
  @keyframes vuubgup1 {
3
127
  0% {
4
128
  background-color: var(--salt-sentiment-positive-foreground-informative);
@@ -1,25 +1,94 @@
1
1
  import { getMovingValueDirection, isTypeDescriptor, isValidNumber } from "@vuu-ui/vuu-utils";
2
- import { useEffect, useRef } from "react";
3
- const INITIAL_VALUE = [
4
- void 0,
5
- void 0,
6
- void 0,
7
- void 0
8
- ];
2
+ import { useEffect, useRef, useState } from "react";
3
+ const DEFAULT_MIN_FLASH_INTERVAL = 1000;
4
+ const DEFAULT_HOT_INTERVAL = 500;
5
+ const DEFAULT_HOT_EXIT_DELAY = 1000;
6
+ const isUp = (direction)=>"up1" === direction || "up2" === direction;
7
+ const isDown = (direction)=>"down1" === direction || "down2" === direction;
8
+ const getRendererSetting = ({ type }, name, defaultValue)=>{
9
+ if (isTypeDescriptor(type) && type.renderer) {
10
+ const value = type.renderer[name];
11
+ if ("number" == typeof value) return value;
12
+ }
13
+ return defaultValue;
14
+ };
15
+ const COOL_DOWN_RESOLUTION = 100;
16
+ const coolDowns = new Map();
17
+ let coolDownTimer;
18
+ const runCoolDowns = ()=>{
19
+ const now = performance.now();
20
+ for (const [owner, entry] of coolDowns)if (entry.until <= now) {
21
+ coolDowns.delete(owner);
22
+ entry.coolDown();
23
+ }
24
+ if (0 === coolDowns.size && void 0 !== coolDownTimer) {
25
+ clearInterval(coolDownTimer);
26
+ coolDownTimer = void 0;
27
+ }
28
+ };
29
+ const scheduleCoolDown = (owner, until, coolDown)=>{
30
+ const entry = coolDowns.get(owner);
31
+ if (entry) entry.until = until;
32
+ else coolDowns.set(owner, {
33
+ until,
34
+ coolDown
35
+ });
36
+ coolDownTimer ??= setInterval(runCoolDowns, COOL_DOWN_RESOLUTION);
37
+ };
9
38
  function useDirection(key, value, column) {
10
39
  const ref = useRef(void 0);
11
- const [prevKey, prevValue, prevColumn, prevDirection] = ref.current || INITIAL_VALUE;
40
+ const [, setCoolDownCount] = useState(0);
41
+ const prev = ref.current;
42
+ const sameCell = prev?.key === key && prev?.column === column;
12
43
  const { type: dataType } = column;
13
44
  const decimals = isTypeDescriptor(dataType) ? dataType.formatting?.decimals : void 0;
14
- const direction = key === prevKey && isValidNumber(value) && isValidNumber(prevValue) && column === prevColumn ? getMovingValueDirection(value, prevDirection, prevValue, decimals) : "";
45
+ const move = prev && sameCell && isValidNumber(value) && isValidNumber(prev.value) ? getMovingValueDirection(value, prev.lastMove, prev.value, decimals) : "";
46
+ const changed = "" !== move;
47
+ const now = performance.now();
48
+ const hotInterval = getRendererSetting(column, "hotInterval", DEFAULT_HOT_INTERVAL);
49
+ let hotUntil = prev && sameCell ? prev.hotUntil : 0;
50
+ let hotDirection = prev && sameCell ? prev.hotDirection : void 0;
51
+ if (prev && changed && now - prev.lastChange < hotInterval) {
52
+ hotUntil = now + getRendererSetting(column, "hotExitDelay", DEFAULT_HOT_EXIT_DELAY);
53
+ hotDirection = isUp(move) ? "up" : "down";
54
+ }
55
+ const hot = now < hotUntil ? hotDirection : void 0;
56
+ const wasHot = sameCell && prev?.hot !== void 0;
57
+ let direction = "";
58
+ let flashStart = 0;
59
+ let cooling;
60
+ if (hot) ;
61
+ else if (prev && wasHot && !changed) cooling = prev.hot;
62
+ else if (prev && sameCell) {
63
+ const sameDirection = isUp(move) && isUp(prev.direction) || isDown(move) && isDown(prev.direction);
64
+ const keepCurrentFlash = sameDirection && now - prev.flashStart < getRendererSetting(column, "minFlashInterval", DEFAULT_MIN_FLASH_INTERVAL);
65
+ direction = keepCurrentFlash ? prev.direction : move;
66
+ flashStart = keepCurrentFlash ? prev.flashStart : move ? now : 0;
67
+ }
68
+ const lastMove = changed ? move : prev?.lastMove ?? "";
69
+ const lastChange = changed ? now : prev && sameCell ? prev.lastChange : 0;
15
70
  useEffect(()=>{
16
- ref.current = [
71
+ ref.current = {
17
72
  key,
18
73
  value,
19
74
  column,
20
- direction
21
- ];
75
+ lastMove,
76
+ direction,
77
+ flashStart,
78
+ lastChange,
79
+ hotUntil,
80
+ hotDirection,
81
+ hot
82
+ };
83
+ if (hot) scheduleCoolDown(ref, hotUntil, ()=>setCoolDownCount((n)=>n + 1));
22
84
  });
23
- return direction;
85
+ useEffect(()=>()=>{
86
+ coolDowns.delete(ref);
87
+ }, []);
88
+ return {
89
+ direction,
90
+ hot,
91
+ cooling
92
+ };
24
93
  }
25
- export { useDirection };
94
+ export { DEFAULT_HOT_EXIT_DELAY, DEFAULT_HOT_INTERVAL, DEFAULT_MIN_FLASH_INTERVAL, useDirection };
@@ -4,7 +4,7 @@ import { useComponentCssInjection } from "@salt-ds/styles";
4
4
  import { useWindow } from "@salt-ds/window";
5
5
  import { IconButton } from "@vuu-ui/vuu-ui-controls";
6
6
  import clsx from "clsx";
7
- import { useCallback } from "react";
7
+ import { useCallback, useLayoutEffect, useRef, useState } from "react";
8
8
  import { useTableContext } from "../table-provider/TableProvider.js";
9
9
  import { buildAggregationMenuItems, buildGroupMenu, buildPinMenuItems, buildSortMenu, buildVisibilityMenuItems, getColumnMenuActionType } from "./column-menu-utils.js";
10
10
  import ColumnMenu from "./ColumnMenu.css";
@@ -17,14 +17,49 @@ const defaultColumnMenuPermissions = {
17
17
  allowRemove: true,
18
18
  allowPin: true
19
19
  };
20
- const ColumnMenu_ColumnMenu = ({ className, column, menuActionHandler: menuActionHandlerProp, menuPermissions: { allowSort, allowGroup, allowAggregation, allowHide, allowRemove, allowPin } = defaultColumnMenuPermissions })=>{
20
+ const stopPropagation = (evt)=>{
21
+ evt.stopPropagation();
22
+ };
23
+ const ColumnMenu_ColumnMenu = (props)=>{
21
24
  const targetWindow = useWindow();
22
25
  useComponentCssInjection({
23
26
  testId: "vuu-column-menu",
24
27
  css: ColumnMenu,
25
28
  window: targetWindow
26
29
  });
30
+ const [mountReason, setMountReason] = useState();
31
+ const mountOnKeyboardFocus = useCallback((evt)=>{
32
+ if (evt.currentTarget.matches(":focus-visible")) setMountReason("focus");
33
+ }, []);
34
+ const mountOnClick = useCallback((evt)=>{
35
+ evt.stopPropagation();
36
+ setMountReason("click");
37
+ }, []);
38
+ return mountReason ? /*#__PURE__*/ jsx(ColumnMenuContent, {
39
+ ...props,
40
+ focusTriggerOnMount: "focus" === mountReason,
41
+ openOnMount: "click" === mountReason
42
+ }) : /*#__PURE__*/ jsx(ColumnMenuButton, {
43
+ className: props.className,
44
+ onClick: mountOnClick,
45
+ onFocus: mountOnKeyboardFocus
46
+ });
47
+ };
48
+ const ColumnMenuButton = ({ className, ...props })=>/*#__PURE__*/ jsx(IconButton, {
49
+ appearance: "transparent",
50
+ "data-embedded": true,
51
+ icon: "more-vert",
52
+ sentiment: "neutral",
53
+ "aria-label": "Open Column Menu",
54
+ ...props,
55
+ className: clsx(classBase, className)
56
+ });
57
+ const ColumnMenuContent = ({ className, column, focusTriggerOnMount, openOnMount, menuActionHandler: menuActionHandlerProp, menuPermissions: { allowSort, allowGroup, allowAggregation, allowHide, allowRemove, allowPin } = defaultColumnMenuPermissions })=>{
27
58
  const { dataSource, menuActionHandler } = useTableContext(true);
59
+ const triggerRef = useRef(null);
60
+ useLayoutEffect(()=>{
61
+ if (focusTriggerOnMount) triggerRef.current?.focus();
62
+ }, []);
28
63
  const menuActionClickHandler = useCallback((evt)=>{
29
64
  const columnMenuActionType = getColumnMenuActionType(evt.target);
30
65
  if (menuActionHandlerProp?.(columnMenuActionType, column) !== true) return menuActionHandler(columnMenuActionType, column);
@@ -38,20 +73,14 @@ const ColumnMenu_ColumnMenu = ({ className, column, menuActionHandler: menuActio
38
73
  const aggregationMenu = buildAggregationMenuItems(column, dataSource, menuActionClickHandler, allowAggregation);
39
74
  const visibilityMenuItems = buildVisibilityMenuItems(column, menuActionClickHandler, allowHide, allowRemove);
40
75
  const pinMenu = buildPinMenuItems(column, menuActionClickHandler, allowPin);
41
- const handleClick = useCallback((evt)=>{
42
- evt.stopPropagation();
43
- }, []);
44
76
  return /*#__PURE__*/ jsxs(Menu, {
77
+ defaultOpen: openOnMount,
45
78
  children: [
46
79
  /*#__PURE__*/ jsx(MenuTrigger, {
47
- children: /*#__PURE__*/ jsx(IconButton, {
48
- appearance: "transparent",
49
- className: clsx(classBase, className),
50
- "data-embedded": true,
51
- icon: "more-vert",
52
- sentiment: "neutral",
53
- "aria-label": "Open Column Menu",
54
- onClick: handleClick
80
+ children: /*#__PURE__*/ jsx(ColumnMenuButton, {
81
+ className: className,
82
+ onClick: stopPropagation,
83
+ ref: triggerRef
55
84
  })
56
85
  }),
57
86
  /*#__PURE__*/ jsxs(MenuPanel, {
@@ -1,3 +1,32 @@
1
1
  import { RuntimeColumnDescriptor } from "@vuu-ui/vuu-table-types";
2
2
  import { valueChangeDirection } from "@vuu-ui/vuu-utils";
3
- export declare function useDirection(key: string, value: unknown, column: RuntimeColumnDescriptor): valueChangeDirection;
3
+ /**
4
+ * A flash is not restarted if the cell flashed in the same direction more
5
+ * recently than this. While a cell keeps changing, its current flash keeps
6
+ * fading rather than restarting on every change. Restarting animations is
7
+ * the main cost of flashing cells at high update rates and adds little
8
+ * information when a value changes several times a second. A change of
9
+ * direction always flashes immediately. Configurable per column with
10
+ * renderer.minFlashInterval (ms), 0 restarts on every change.
11
+ */
12
+ export declare const DEFAULT_MIN_FLASH_INTERVAL = 1000;
13
+ /**
14
+ * A cell whose value changes again within this many ms of its previous
15
+ * change is 'hot': instead of flashing it shows a steady tint in the
16
+ * direction of its latest move, with no animation. Configurable per column
17
+ * with renderer.hotInterval (ms), 0 disables the hot state.
18
+ */
19
+ export declare const DEFAULT_HOT_INTERVAL = 500;
20
+ /**
21
+ * A hot cell cools down after this many ms without a change: its pale tint
22
+ * fades out. It does not flash, a bold flash always means a move after a
23
+ * quiet spell. Configurable with renderer.hotExitDelay (ms).
24
+ */
25
+ export declare const DEFAULT_HOT_EXIT_DELAY = 1000;
26
+ export type HotDirection = "up" | "down";
27
+ export declare function useDirection(key: string, value: unknown, column: RuntimeColumnDescriptor): {
28
+ direction: valueChangeDirection;
29
+ hot?: HotDirection;
30
+ /** a hot cell that has just gone quiet, its tint fades out */
31
+ cooling?: HotDirection;
32
+ };
@@ -7,4 +7,16 @@ export interface ColumnMenuProps extends HTMLAttributes<HTMLSpanElement> {
7
7
  menuActionHandler?: MenuActionHandler<ColumnMenuActionType, ColumnDescriptor>;
8
8
  menuPermissions?: ColumnMenuPermissions;
9
9
  }
10
- export declare const ColumnMenu: ({ className, column, menuActionHandler: menuActionHandlerProp, menuPermissions: { allowSort, allowGroup, allowAggregation, allowHide, allowRemove, allowPin, }, }: ColumnMenuProps) => import("react/jsx-runtime").JSX.Element;
10
+ /**
11
+ * Renders only the trigger button until a user shows interest in the menu.
12
+ * A table has a column menu in every header cell, and the full menu (popup,
13
+ * menu items, table context) is only needed for the one a user opens.
14
+ *
15
+ * A click mounts the full menu, already open. Keyboard focus mounts it
16
+ * without opening it, and passes focus on to the new trigger (mounting
17
+ * replaces the button), so the key press that follows reaches the real menu
18
+ * trigger and opens the menu with focus inside it. Focus from a mouse click
19
+ * is not :focus-visible and is left to the click, so the button is not
20
+ * replaced between mouse down and mouse up.
21
+ */
22
+ export declare const ColumnMenu: (props: ColumnMenuProps) => import("react/jsx-runtime").JSX.Element;