@lensui/lens-table 0.1.96 → 0.1.98

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/index.cjs CHANGED
@@ -953,6 +953,42 @@ function TextEditor({ value, type, min, max, integer = false, style, labels, onC
953
953
  var import_react6 = require("react");
954
954
  var import_react_dom = require("react-dom");
955
955
  var import_jsx_runtime7 = require("react/jsx-runtime");
956
+ var getLineStart = (value, position) => {
957
+ if (position <= 0) return 0;
958
+ return Math.max(
959
+ value.lastIndexOf("\n", position - 1),
960
+ value.lastIndexOf("\r", position - 1)
961
+ ) + 1;
962
+ };
963
+ var getLineEnd = (value, start) => {
964
+ const carriageReturn = value.indexOf("\r", start);
965
+ const lineFeed = value.indexOf("\n", start);
966
+ if (carriageReturn < 0) return lineFeed < 0 ? value.length : lineFeed;
967
+ if (lineFeed < 0) return carriageReturn;
968
+ return Math.min(carriageReturn, lineFeed);
969
+ };
970
+ var getPreviousLine = (value, currentStart) => {
971
+ if (currentStart <= 0) return null;
972
+ let previousEnd = currentStart - 1;
973
+ if (value[previousEnd] === "\n" && previousEnd > 0 && value[previousEnd - 1] === "\r") {
974
+ previousEnd -= 1;
975
+ }
976
+ return {
977
+ start: getLineStart(value, previousEnd),
978
+ end: previousEnd
979
+ };
980
+ };
981
+ var getNextLine = (value, currentEnd) => {
982
+ if (currentEnd >= value.length) return null;
983
+ let nextStart = currentEnd + 1;
984
+ if (value[currentEnd] === "\r" && nextStart < value.length && value[nextStart] === "\n") {
985
+ nextStart += 1;
986
+ }
987
+ return {
988
+ start: nextStart,
989
+ end: getLineEnd(value, nextStart)
990
+ };
991
+ };
956
992
  function TextAreaEditor({
957
993
  value,
958
994
  title,
@@ -969,7 +1005,10 @@ function TextAreaEditor({
969
1005
  const inputRef = (0, import_react6.useRef)(null);
970
1006
  const textareaRef = (0, import_react6.useRef)(null);
971
1007
  const lastLineStart = inline ? Math.max(value.lastIndexOf("\n"), value.lastIndexOf("\r")) + 1 : 0;
972
- const collapsedValue = inline ? value.slice(lastLineStart) : value;
1008
+ const [collapsedLineStart, setCollapsedLineStart] = (0, import_react6.useState)(lastLineStart);
1009
+ const activeLineStart = inline ? Math.min(collapsedLineStart, value.length) : 0;
1010
+ const activeLineEnd = inline ? getLineEnd(value, activeLineStart) : value.length;
1011
+ const collapsedValue = inline ? value.slice(activeLineStart, activeLineEnd) : value;
973
1012
  const selectionRef = (0, import_react6.useRef)(null);
974
1013
  const inlineHeaderHeight = typeof style.height === "number" ? style.height : 34;
975
1014
  const editorStyle = inline && open ? {
@@ -979,6 +1018,32 @@ function TextAreaEditor({
979
1018
  } : style;
980
1019
  const handleKeyDown = (event) => {
981
1020
  event.stopPropagation();
1021
+ if (inline && event.key === "ArrowLeft" && !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey && event.currentTarget.selectionStart === 0 && event.currentTarget.selectionEnd === 0) {
1022
+ const previousLine = getPreviousLine(value, activeLineStart);
1023
+ if (previousLine) {
1024
+ event.preventDefault();
1025
+ selectionRef.current = {
1026
+ start: previousLine.end,
1027
+ end: previousLine.end,
1028
+ direction: "none"
1029
+ };
1030
+ setCollapsedLineStart(previousLine.start);
1031
+ return;
1032
+ }
1033
+ }
1034
+ if (inline && event.key === "ArrowRight" && !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey && event.currentTarget.selectionStart === collapsedValue.length && event.currentTarget.selectionEnd === collapsedValue.length) {
1035
+ const nextLine = getNextLine(value, activeLineEnd);
1036
+ if (nextLine) {
1037
+ event.preventDefault();
1038
+ selectionRef.current = {
1039
+ start: nextLine.start,
1040
+ end: nextLine.start,
1041
+ direction: "none"
1042
+ };
1043
+ setCollapsedLineStart(nextLine.start);
1044
+ return;
1045
+ }
1046
+ }
982
1047
  if (event.key === "Enter") onCommit(value);
983
1048
  if (event.key === "Escape") onCancel();
984
1049
  };
@@ -997,21 +1062,20 @@ function TextAreaEditor({
997
1062
  if (!control) return;
998
1063
  const selection = selectionRef.current;
999
1064
  const length = control.value.length;
1000
- const offset = open ? 0 : lastLineStart;
1065
+ const offset = open ? 0 : activeLineStart;
1001
1066
  control.focus();
1002
1067
  control.setSelectionRange(
1003
1068
  Math.max(0, Math.min(selection.start - offset, length)),
1004
1069
  Math.max(0, Math.min(selection.end - offset, length)),
1005
1070
  selection.direction
1006
1071
  );
1007
- }, [inline, lastLineStart, open]);
1072
+ }, [activeLineStart, inline, open]);
1008
1073
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1009
1074
  "div",
1010
1075
  {
1011
1076
  className: `rvg-native-editor rvg-textarea-editor${inline && open ? " is-inline-expanded" : ""}`,
1012
1077
  style: editorStyle,
1013
1078
  children: [
1014
- inline && !open && lastLineStart > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "rvg-textarea-collapsed-prefix", "aria-hidden": "true", children: "\u21B5" }),
1015
1079
  !(inline && open) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1016
1080
  "input",
1017
1081
  {
@@ -1020,12 +1084,12 @@ function TextAreaEditor({
1020
1084
  autoFocus: true,
1021
1085
  maxLength,
1022
1086
  onChange: (event) => onChange(
1023
- inline ? `${value.slice(0, lastLineStart)}${event.target.value}` : event.target.value
1087
+ inline ? `${value.slice(0, activeLineStart)}${event.target.value}${value.slice(activeLineEnd)}` : event.target.value
1024
1088
  ),
1025
1089
  onKeyDown: handleKeyDown
1026
1090
  }
1027
1091
  ),
1028
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1092
+ (!inline || !open) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1029
1093
  "button",
1030
1094
  {
1031
1095
  type: "button",
@@ -1041,11 +1105,7 @@ function TextAreaEditor({
1041
1105
  setOpen(true);
1042
1106
  return;
1043
1107
  }
1044
- if (open) {
1045
- textareaRef.current?.focus();
1046
- return;
1047
- }
1048
- rememberSelection(inputRef.current, lastLineStart);
1108
+ rememberSelection(inputRef.current, activeLineStart);
1049
1109
  setOpen(true);
1050
1110
  },
1051
1111
  children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MultilineEditorIcon, {})
@@ -1062,13 +1122,24 @@ function TextAreaEditor({
1062
1122
  autoFocus: true,
1063
1123
  maxLength,
1064
1124
  onPointerDown: (event) => event.stopPropagation(),
1065
- onChange: (event) => onChange(event.target.value),
1125
+ onChange: (event) => {
1126
+ rememberSelection(event.currentTarget);
1127
+ onChange(event.currentTarget.value);
1128
+ },
1066
1129
  onKeyDown: (event) => {
1067
1130
  event.stopPropagation();
1068
1131
  if ((event.metaKey || event.ctrlKey) && event.key === "Enter")
1069
1132
  onCommit(value);
1070
1133
  if (event.key === "Escape") {
1071
1134
  rememberSelection(event.currentTarget);
1135
+ if (event.currentTarget.selectionStart !== null) {
1136
+ setCollapsedLineStart(
1137
+ getLineStart(
1138
+ event.currentTarget.value,
1139
+ event.currentTarget.selectionStart
1140
+ )
1141
+ );
1142
+ }
1072
1143
  setOpen(false);
1073
1144
  }
1074
1145
  }
package/dist/index.css CHANGED
@@ -2794,9 +2794,6 @@
2794
2794
  cursor: pointer;
2795
2795
  transform: translateY(-50%);
2796
2796
  }
2797
- .rvg-textarea-editor.is-inline-expanded .rvg-textarea-trigger {
2798
- top: calc(var(--rvg-textarea-inline-header-height) / 2);
2799
- }
2800
2797
  .rvg-multiline-icon {
2801
2798
  width: 13px;
2802
2799
  height: 13px;
@@ -2809,7 +2806,7 @@
2809
2806
  min-width: 0;
2810
2807
  min-height: 0;
2811
2808
  margin: 0;
2812
- padding: 0 24px 8px 4px;
2809
+ padding: 0 4px 8px;
2813
2810
  resize: none;
2814
2811
  border: 0;
2815
2812
  border-radius: 0;
@@ -2824,6 +2821,20 @@
2824
2821
  line-height: var(--rvg-textarea-inline-header-height);
2825
2822
  box-shadow: none;
2826
2823
  box-sizing: border-box;
2824
+ scrollbar-width: thin;
2825
+ scrollbar-color: #aeb3b8 transparent;
2826
+ }
2827
+ .rvg-textarea-inline::-webkit-scrollbar {
2828
+ width: 5px;
2829
+ height: 5px;
2830
+ }
2831
+ .rvg-textarea-inline::-webkit-scrollbar-track,
2832
+ .rvg-textarea-inline::-webkit-scrollbar-corner {
2833
+ background: transparent;
2834
+ }
2835
+ .rvg-textarea-inline::-webkit-scrollbar-thumb {
2836
+ border-radius: 999px;
2837
+ background: #aeb3b8;
2827
2838
  }
2828
2839
  .rvg-textarea-backdrop {
2829
2840
  position: fixed;
package/dist/index.js CHANGED
@@ -927,6 +927,42 @@ import {
927
927
  } from "react";
928
928
  import { createPortal } from "react-dom";
929
929
  import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
930
+ var getLineStart = (value, position) => {
931
+ if (position <= 0) return 0;
932
+ return Math.max(
933
+ value.lastIndexOf("\n", position - 1),
934
+ value.lastIndexOf("\r", position - 1)
935
+ ) + 1;
936
+ };
937
+ var getLineEnd = (value, start) => {
938
+ const carriageReturn = value.indexOf("\r", start);
939
+ const lineFeed = value.indexOf("\n", start);
940
+ if (carriageReturn < 0) return lineFeed < 0 ? value.length : lineFeed;
941
+ if (lineFeed < 0) return carriageReturn;
942
+ return Math.min(carriageReturn, lineFeed);
943
+ };
944
+ var getPreviousLine = (value, currentStart) => {
945
+ if (currentStart <= 0) return null;
946
+ let previousEnd = currentStart - 1;
947
+ if (value[previousEnd] === "\n" && previousEnd > 0 && value[previousEnd - 1] === "\r") {
948
+ previousEnd -= 1;
949
+ }
950
+ return {
951
+ start: getLineStart(value, previousEnd),
952
+ end: previousEnd
953
+ };
954
+ };
955
+ var getNextLine = (value, currentEnd) => {
956
+ if (currentEnd >= value.length) return null;
957
+ let nextStart = currentEnd + 1;
958
+ if (value[currentEnd] === "\r" && nextStart < value.length && value[nextStart] === "\n") {
959
+ nextStart += 1;
960
+ }
961
+ return {
962
+ start: nextStart,
963
+ end: getLineEnd(value, nextStart)
964
+ };
965
+ };
930
966
  function TextAreaEditor({
931
967
  value,
932
968
  title,
@@ -943,7 +979,10 @@ function TextAreaEditor({
943
979
  const inputRef = useRef4(null);
944
980
  const textareaRef = useRef4(null);
945
981
  const lastLineStart = inline ? Math.max(value.lastIndexOf("\n"), value.lastIndexOf("\r")) + 1 : 0;
946
- const collapsedValue = inline ? value.slice(lastLineStart) : value;
982
+ const [collapsedLineStart, setCollapsedLineStart] = useState4(lastLineStart);
983
+ const activeLineStart = inline ? Math.min(collapsedLineStart, value.length) : 0;
984
+ const activeLineEnd = inline ? getLineEnd(value, activeLineStart) : value.length;
985
+ const collapsedValue = inline ? value.slice(activeLineStart, activeLineEnd) : value;
947
986
  const selectionRef = useRef4(null);
948
987
  const inlineHeaderHeight = typeof style.height === "number" ? style.height : 34;
949
988
  const editorStyle = inline && open ? {
@@ -953,6 +992,32 @@ function TextAreaEditor({
953
992
  } : style;
954
993
  const handleKeyDown = (event) => {
955
994
  event.stopPropagation();
995
+ if (inline && event.key === "ArrowLeft" && !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey && event.currentTarget.selectionStart === 0 && event.currentTarget.selectionEnd === 0) {
996
+ const previousLine = getPreviousLine(value, activeLineStart);
997
+ if (previousLine) {
998
+ event.preventDefault();
999
+ selectionRef.current = {
1000
+ start: previousLine.end,
1001
+ end: previousLine.end,
1002
+ direction: "none"
1003
+ };
1004
+ setCollapsedLineStart(previousLine.start);
1005
+ return;
1006
+ }
1007
+ }
1008
+ if (inline && event.key === "ArrowRight" && !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey && event.currentTarget.selectionStart === collapsedValue.length && event.currentTarget.selectionEnd === collapsedValue.length) {
1009
+ const nextLine = getNextLine(value, activeLineEnd);
1010
+ if (nextLine) {
1011
+ event.preventDefault();
1012
+ selectionRef.current = {
1013
+ start: nextLine.start,
1014
+ end: nextLine.start,
1015
+ direction: "none"
1016
+ };
1017
+ setCollapsedLineStart(nextLine.start);
1018
+ return;
1019
+ }
1020
+ }
956
1021
  if (event.key === "Enter") onCommit(value);
957
1022
  if (event.key === "Escape") onCancel();
958
1023
  };
@@ -971,21 +1036,20 @@ function TextAreaEditor({
971
1036
  if (!control) return;
972
1037
  const selection = selectionRef.current;
973
1038
  const length = control.value.length;
974
- const offset = open ? 0 : lastLineStart;
1039
+ const offset = open ? 0 : activeLineStart;
975
1040
  control.focus();
976
1041
  control.setSelectionRange(
977
1042
  Math.max(0, Math.min(selection.start - offset, length)),
978
1043
  Math.max(0, Math.min(selection.end - offset, length)),
979
1044
  selection.direction
980
1045
  );
981
- }, [inline, lastLineStart, open]);
1046
+ }, [activeLineStart, inline, open]);
982
1047
  return /* @__PURE__ */ jsxs7(
983
1048
  "div",
984
1049
  {
985
1050
  className: `rvg-native-editor rvg-textarea-editor${inline && open ? " is-inline-expanded" : ""}`,
986
1051
  style: editorStyle,
987
1052
  children: [
988
- inline && !open && lastLineStart > 0 && /* @__PURE__ */ jsx7("span", { className: "rvg-textarea-collapsed-prefix", "aria-hidden": "true", children: "\u21B5" }),
989
1053
  !(inline && open) && /* @__PURE__ */ jsx7(
990
1054
  "input",
991
1055
  {
@@ -994,12 +1058,12 @@ function TextAreaEditor({
994
1058
  autoFocus: true,
995
1059
  maxLength,
996
1060
  onChange: (event) => onChange(
997
- inline ? `${value.slice(0, lastLineStart)}${event.target.value}` : event.target.value
1061
+ inline ? `${value.slice(0, activeLineStart)}${event.target.value}${value.slice(activeLineEnd)}` : event.target.value
998
1062
  ),
999
1063
  onKeyDown: handleKeyDown
1000
1064
  }
1001
1065
  ),
1002
- /* @__PURE__ */ jsx7(
1066
+ (!inline || !open) && /* @__PURE__ */ jsx7(
1003
1067
  "button",
1004
1068
  {
1005
1069
  type: "button",
@@ -1015,11 +1079,7 @@ function TextAreaEditor({
1015
1079
  setOpen(true);
1016
1080
  return;
1017
1081
  }
1018
- if (open) {
1019
- textareaRef.current?.focus();
1020
- return;
1021
- }
1022
- rememberSelection(inputRef.current, lastLineStart);
1082
+ rememberSelection(inputRef.current, activeLineStart);
1023
1083
  setOpen(true);
1024
1084
  },
1025
1085
  children: /* @__PURE__ */ jsx7(MultilineEditorIcon, {})
@@ -1036,13 +1096,24 @@ function TextAreaEditor({
1036
1096
  autoFocus: true,
1037
1097
  maxLength,
1038
1098
  onPointerDown: (event) => event.stopPropagation(),
1039
- onChange: (event) => onChange(event.target.value),
1099
+ onChange: (event) => {
1100
+ rememberSelection(event.currentTarget);
1101
+ onChange(event.currentTarget.value);
1102
+ },
1040
1103
  onKeyDown: (event) => {
1041
1104
  event.stopPropagation();
1042
1105
  if ((event.metaKey || event.ctrlKey) && event.key === "Enter")
1043
1106
  onCommit(value);
1044
1107
  if (event.key === "Escape") {
1045
1108
  rememberSelection(event.currentTarget);
1109
+ if (event.currentTarget.selectionStart !== null) {
1110
+ setCollapsedLineStart(
1111
+ getLineStart(
1112
+ event.currentTarget.value,
1113
+ event.currentTarget.selectionStart
1114
+ )
1115
+ );
1116
+ }
1046
1117
  setOpen(false);
1047
1118
  }
1048
1119
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lensui/lens-table",
3
- "version": "0.1.96",
3
+ "version": "0.1.98",
4
4
  "description": "A lightweight, canvas-rendered React table component for LensUI.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",