@canvas-components/react-components 0.3.6 → 0.3.8

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
@@ -319,6 +319,7 @@ function ReactPopup(props) {
319
319
  style,
320
320
  surfaceClassName,
321
321
  surfaceStyle,
322
+ constrainHeight = false,
322
323
  zIndex = 1200
323
324
  } = props;
324
325
  const { scale: contentScale } = useReactContentScale();
@@ -340,6 +341,7 @@ function ReactPopup(props) {
340
341
  return;
341
342
  }
342
343
  const nextPosition = resolvePopupPosition({
344
+ constrainHeight,
343
345
  anchor: nextAnchor,
344
346
  contentScale,
345
347
  matchAnchorWidth,
@@ -349,7 +351,7 @@ function ReactPopup(props) {
349
351
  popupRect: resolvePopupSurfaceRect(surfaceRef.current, contentScale)
350
352
  });
351
353
  setPosition((prev) => {
352
- if (prev?.placement === nextPosition.placement && prev?.style.left === nextPosition.style.left && prev?.style.top === nextPosition.style.top && prev?.style.width === nextPosition.style.width && prev?.style.minWidth === nextPosition.style.minWidth) {
354
+ if (prev?.placement === nextPosition.placement && prev?.style.left === nextPosition.style.left && prev?.style.top === nextPosition.style.top && prev?.style.width === nextPosition.style.width && prev?.style.minWidth === nextPosition.style.minWidth && prev?.style.maxHeight === nextPosition.style.maxHeight) {
353
355
  return prev;
354
356
  }
355
357
  return nextPosition;
@@ -376,6 +378,7 @@ function ReactPopup(props) {
376
378
  anchorRect,
377
379
  anchorRef,
378
380
  contentScale,
381
+ constrainHeight,
379
382
  matchAnchorWidth,
380
383
  minWidth,
381
384
  offset,
@@ -392,6 +395,7 @@ function ReactPopup(props) {
392
395
  return;
393
396
  }
394
397
  const nextPosition = resolvePopupPosition({
398
+ constrainHeight,
395
399
  anchor: nextAnchor,
396
400
  contentScale,
397
401
  matchAnchorWidth,
@@ -401,7 +405,7 @@ function ReactPopup(props) {
401
405
  popupRect: resolvePopupSurfaceRect(surfaceRef.current, contentScale)
402
406
  });
403
407
  setPosition((prev) => {
404
- if (prev?.placement === nextPosition.placement && prev?.style.left === nextPosition.style.left && prev?.style.top === nextPosition.style.top && prev?.style.width === nextPosition.style.width && prev?.style.minWidth === nextPosition.style.minWidth) {
408
+ if (prev?.placement === nextPosition.placement && prev?.style.left === nextPosition.style.left && prev?.style.top === nextPosition.style.top && prev?.style.width === nextPosition.style.width && prev?.style.minWidth === nextPosition.style.minWidth && prev?.style.maxHeight === nextPosition.style.maxHeight) {
405
409
  return prev;
406
410
  }
407
411
  return nextPosition;
@@ -419,6 +423,7 @@ function ReactPopup(props) {
419
423
  anchorRect,
420
424
  anchorRef,
421
425
  contentScale,
426
+ constrainHeight,
422
427
  matchAnchorWidth,
423
428
  minWidth,
424
429
  offset,
@@ -484,7 +489,7 @@ function ReactPopup(props) {
484
489
  transition.className,
485
490
  surfaceClassName
486
491
  ),
487
- style: surfaceStyle,
492
+ style: resolvePopupSurfaceStyle(surfaceStyle, position.style.maxHeight),
488
493
  children
489
494
  }
490
495
  )
@@ -513,7 +518,8 @@ function resolvePopupPosition(params) {
513
518
  matchAnchorWidth ? anchor.width : 0
514
519
  );
515
520
  const popupWidth = preferredVisualWidth;
516
- const popupHeight = popupRect?.height ?? 0;
521
+ const maxVisualHeight = Math.max(0, viewportHeight - margin * 2);
522
+ const popupHeight = params.constrainHeight ? Math.min(popupRect?.height ?? 0, maxVisualHeight) : popupRect?.height ?? 0;
517
523
  const isHorizontalPlacement = placement.startsWith("left") || placement.startsWith("right");
518
524
  const preferredVertical = placement.startsWith("top") ? "top" : placement.endsWith("Top") ? "top" : "bottom";
519
525
  const preferredTop = resolveRawTop({
@@ -558,6 +564,7 @@ function resolvePopupPosition(params) {
558
564
  vertical: resolvedVertical
559
565
  }),
560
566
  style: {
567
+ ...params.constrainHeight ? { maxHeight: toContentLayoutSize(maxVisualHeight, contentScale) } : {},
561
568
  left,
562
569
  top,
563
570
  width: matchAnchorWidth ? layoutAnchorWidth : void 0,
@@ -565,6 +572,19 @@ function resolvePopupPosition(params) {
565
572
  }
566
573
  };
567
574
  }
575
+ function resolvePopupSurfaceStyle(style, viewportMaxHeight) {
576
+ if (typeof viewportMaxHeight !== "number") return style;
577
+ const custom = style?.maxHeight;
578
+ const maxHeight = typeof custom === "number" ? Math.min(custom, viewportMaxHeight) : typeof custom === "string" && custom !== "none" ? `min(${custom}, ${viewportMaxHeight}px)` : viewportMaxHeight;
579
+ return {
580
+ ...style,
581
+ boxSizing: "border-box",
582
+ minHeight: 0,
583
+ maxHeight,
584
+ overflowY: "auto",
585
+ overscrollBehaviorY: "contain"
586
+ };
587
+ }
568
588
  function resolvePlacement(params) {
569
589
  const { horizontal, isHorizontalPlacement, vertical } = params;
570
590
  if (isHorizontalPlacement) {
@@ -714,7 +734,7 @@ var ReactVirtualList = React.forwardRef(function ReactVirtualListInner(props, re
714
734
  });
715
735
 
716
736
  // src/components/select/style.css
717
- styleInject('@import "../../styles/variables.css";\n.canvas-react-select-wrap {\n position: relative;\n display: inline-flex;\n width: 100%;\n height: 100%;\n}\n.canvas-react-select {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n height: var(--canvas-react-control-height);\n padding: var(--canvas-react-control-padding-block, 0px) var(--canvas-react-control-padding-inline, 11px);\n border: 1px solid var(--canvas-react-color-border);\n border-radius: var(--canvas-react-radius-sm);\n background: var(--canvas-react-color-bg);\n color: var(--canvas-react-color-text);\n font-size: var(--canvas-react-font-size);\n outline: none;\n cursor: pointer;\n transition:\n border-color 0.2s ease,\n box-shadow 0.2s ease,\n background-color 0.2s ease;\n}\n.canvas-react-select-input-wrap {\n flex: 1 1 auto;\n width: 100%;\n height: 100%;\n border: none;\n background: transparent;\n box-shadow: none;\n}\n.canvas-react-select .canvas-react-input-affix-wrapper {\n height: 100%;\n min-height: 0;\n}\n.canvas-react-select-input-wrap:hover,\n.canvas-react-select-input-wrap:focus-within {\n border-color: transparent;\n box-shadow: none;\n}\n.canvas-react-select-input {\n width: 100%;\n min-width: 0;\n height: 100%;\n padding: 0;\n line-height: normal;\n}\n.canvas-react-select-input::placeholder {\n color: #9ca3af;\n}\n.canvas-react-select:hover {\n border-color: var(--canvas-react-color-primary-hover);\n}\n.canvas-react-select:focus {\n border-color: var(--canvas-react-color-primary);\n box-shadow: var(--canvas-react-shadow-focus);\n}\n.canvas-react-select-open {\n border-color: var(--canvas-react-color-primary);\n box-shadow: var(--canvas-react-shadow-focus);\n}\n.canvas-react-select-disabled {\n color: #9ca3af;\n background: #fafafa;\n cursor: not-allowed;\n}\n.canvas-react-select-actions {\n position: relative;\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n width: 1em;\n min-width: 12px;\n height: 1em;\n min-height: 12px;\n margin-left: max(6px, calc(var(--canvas-react-control-padding-inline, 11px) * 0.5));\n}\n.canvas-react-select-arrow {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 0.5em;\n height: 0.5em;\n min-width: 6px;\n min-height: 6px;\n border-right: 1.5px solid var(--canvas-react-color-text-muted);\n border-bottom: 1.5px solid var(--canvas-react-color-text-muted);\n transform: translate(-50%, -58%) rotate(45deg);\n opacity: 1;\n transition:\n opacity 0.18s ease,\n transform 0.18s ease,\n border-color 0.18s ease;\n}\n.canvas-react-select:hover .canvas-react-select-arrow,\n.canvas-react-select-open .canvas-react-select-arrow {\n border-color: #6b7280;\n}\n.canvas-react-select-arrow-open {\n border-color: #6b7280;\n transform: translate(-50%, -42%) rotate(225deg);\n}\n.canvas-react-select-clear {\n position: absolute;\n top: 50%;\n left: 50%;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 12px;\n height: 12px;\n padding: 0;\n border: none;\n background: transparent;\n color: #9ca3af;\n opacity: 0;\n pointer-events: none;\n cursor: pointer;\n transform: translate(-50%, -50%) rotate(0deg);\n transition:\n color 0.2s ease,\n opacity 0.2s ease,\n transform 0.18s ease;\n}\n.canvas-react-select-clear:hover {\n color: #6b7280;\n transform: translate(-50%, -50%) rotate(90deg);\n}\n.canvas-react-select:hover .canvas-react-select-clear,\n.canvas-react-select-open .canvas-react-select-clear,\n.canvas-react-select:focus-within .canvas-react-select-clear {\n opacity: 1;\n pointer-events: auto;\n}\n.canvas-react-select:hover .canvas-react-select-actions-clearable .canvas-react-select-arrow,\n.canvas-react-select-open .canvas-react-select-actions-clearable .canvas-react-select-arrow,\n.canvas-react-select:focus-within .canvas-react-select-actions-clearable .canvas-react-select-arrow {\n opacity: 0;\n}\n.canvas-react-select-clear-icon,\n.canvas-react-select-clear-icon::before {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 8px;\n height: 1.25px;\n margin-top: -0.625px;\n margin-left: -4px;\n border-radius: 999px;\n background: currentColor;\n content: "";\n}\n.canvas-react-select-clear-icon {\n transform: rotate(45deg);\n}\n.canvas-react-select-clear-icon::before {\n transform: rotate(90deg);\n}\n.canvas-react-select-dropdown {\n padding: 4px;\n}\n.canvas-react-select-list {\n position: relative;\n overflow-y: auto;\n}\n.canvas-react-select-list-inner {\n position: relative;\n}\n.canvas-react-select-option {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n width: 100%;\n padding: 0 11px;\n border-radius: var(--canvas-react-radius-sm);\n color: var(--canvas-react-color-text);\n font-size: var(--canvas-react-font-size);\n cursor: pointer;\n}\n.canvas-react-select-option:hover,\n.canvas-react-select-option-active {\n background: var(--canvas-react-color-bg-hover);\n}\n.canvas-react-select-option-selected {\n background: var(--canvas-react-color-bg-active);\n}\n.canvas-react-select-option-searching {\n color: var(--canvas-react-color-text);\n}\n.canvas-react-select-option-searching:hover,\n.canvas-react-select-option-searching.canvas-react-select-option-active {\n background: var(--canvas-react-color-bg-active);\n}\n.canvas-react-select-option-disabled {\n color: #9ca3af;\n cursor: not-allowed;\n}\n.canvas-react-select-option-highlight {\n color: var(--canvas-react-color-primary);\n font-weight: 600;\n}\n.canvas-react-select-option-disabled .canvas-react-select-option-highlight {\n color: inherit;\n}\n.canvas-react-select-empty {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 0 11px;\n color: #9ca3af;\n font-size: var(--canvas-react-font-size);\n}\n');
737
+ styleInject('@import "../../styles/variables.css";\n.canvas-react-select-wrap {\n position: relative;\n display: inline-flex;\n width: 100%;\n height: 100%;\n}\n.canvas-react-select {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n height: var(--canvas-react-control-height);\n padding: var(--canvas-react-control-padding-block, 0px) var(--canvas-react-control-padding-inline, 11px);\n border: 1px solid var(--canvas-react-color-border);\n border-radius: var(--canvas-react-radius-sm);\n background: var(--canvas-react-color-bg);\n color: var(--canvas-react-color-text);\n font-size: var(--canvas-react-font-size);\n outline: none;\n cursor: pointer;\n transition:\n border-color 0.2s ease,\n box-shadow 0.2s ease,\n background-color 0.2s ease;\n}\n.canvas-react-select-input-wrap {\n flex: 1 1 auto;\n width: 100%;\n height: 100%;\n border: none;\n background: transparent;\n box-shadow: none;\n}\n.canvas-react-select .canvas-react-input-affix-wrapper {\n height: 100%;\n min-height: 0;\n}\n.canvas-react-select-input-wrap:hover,\n.canvas-react-select-input-wrap:focus-within {\n border-color: transparent;\n box-shadow: none;\n}\n.canvas-react-select-input {\n width: 100%;\n min-width: 0;\n height: 100%;\n padding: 0;\n line-height: normal;\n}\n.canvas-react-select-input::placeholder {\n color: #9ca3af;\n}\n.canvas-react-select:hover {\n border-color: var(--canvas-react-color-primary-hover);\n}\n.canvas-react-select:focus {\n border-color: var(--canvas-react-color-primary);\n box-shadow: var(--canvas-react-shadow-focus);\n}\n.canvas-react-select-open {\n border-color: var(--canvas-react-color-primary);\n box-shadow: var(--canvas-react-shadow-focus);\n}\n.canvas-react-select-disabled {\n color: #9ca3af;\n background: #fafafa;\n cursor: not-allowed;\n}\n.canvas-react-select-actions {\n position: relative;\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n width: 1em;\n min-width: 12px;\n height: 1em;\n min-height: 12px;\n margin-left: max(6px, calc(var(--canvas-react-control-padding-inline, 11px) * 0.5));\n}\n.canvas-react-select-arrow {\n pointer-events: none;\n position: absolute;\n top: 50%;\n left: 50%;\n width: 0.5em;\n height: 0.5em;\n min-width: 6px;\n min-height: 6px;\n border-right: 1.5px solid var(--canvas-react-color-text-muted);\n border-bottom: 1.5px solid var(--canvas-react-color-text-muted);\n transform: translate(-50%, -58%) rotate(45deg);\n opacity: 1;\n transition:\n opacity 0.18s ease,\n transform 0.18s ease,\n border-color 0.18s ease;\n}\n.canvas-react-select:hover .canvas-react-select-arrow,\n.canvas-react-select-open .canvas-react-select-arrow {\n border-color: #6b7280;\n}\n.canvas-react-select-arrow-open {\n border-color: #6b7280;\n transform: translate(-50%, -42%) rotate(225deg);\n}\n.canvas-react-select-clear {\n position: absolute;\n top: 50%;\n left: 50%;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 12px;\n height: 12px;\n padding: 0;\n border: none;\n background: transparent;\n color: #9ca3af;\n opacity: 0;\n pointer-events: none;\n cursor: pointer;\n transform: translate(-50%, -50%) rotate(0deg);\n transition:\n color 0.2s ease,\n opacity 0.2s ease,\n transform 0.18s ease;\n}\n.canvas-react-select-clear:hover {\n color: #6b7280;\n transform: translate(-50%, -50%) rotate(90deg);\n}\n.canvas-react-select:hover .canvas-react-select-clear,\n.canvas-react-select-open .canvas-react-select-clear,\n.canvas-react-select:focus-within .canvas-react-select-clear,\n.canvas-react-cascader:hover .canvas-react-select-clear,\n.canvas-react-cascader-open .canvas-react-select-clear,\n.canvas-react-cascader:focus-within .canvas-react-select-clear {\n opacity: 1;\n pointer-events: auto;\n}\n.canvas-react-select:hover .canvas-react-select-actions-clearable .canvas-react-select-arrow,\n.canvas-react-select-open .canvas-react-select-actions-clearable .canvas-react-select-arrow,\n.canvas-react-select:focus-within .canvas-react-select-actions-clearable .canvas-react-select-arrow,\n.canvas-react-cascader:hover .canvas-react-select-actions-clearable .canvas-react-select-arrow,\n.canvas-react-cascader-open .canvas-react-select-actions-clearable .canvas-react-select-arrow,\n.canvas-react-cascader:focus-within .canvas-react-select-actions-clearable .canvas-react-select-arrow {\n opacity: 0;\n}\n.canvas-react-select-clear-icon,\n.canvas-react-select-clear-icon::before {\n position: absolute;\n top: 50%;\n left: 50%;\n width: 8px;\n height: 1.25px;\n margin-top: -0.625px;\n margin-left: -4px;\n border-radius: 999px;\n background: currentColor;\n content: "";\n}\n.canvas-react-select-clear-icon {\n transform: rotate(45deg);\n}\n.canvas-react-select-clear-icon::before {\n transform: rotate(90deg);\n}\n.canvas-react-select-dropdown {\n padding: 4px;\n}\n.canvas-react-select-list {\n position: relative;\n overflow-y: auto;\n}\n.canvas-react-select-list-inner {\n position: relative;\n}\n.canvas-react-select-option {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n width: 100%;\n padding: 0 11px;\n border-radius: var(--canvas-react-radius-sm);\n color: var(--canvas-react-color-text);\n font-size: var(--canvas-react-font-size);\n cursor: pointer;\n}\n.canvas-react-select-option:hover,\n.canvas-react-select-option-active {\n background: var(--canvas-react-color-bg-hover);\n}\n.canvas-react-select-option-selected {\n background: var(--canvas-react-color-bg-active);\n}\n.canvas-react-select-option-searching {\n color: var(--canvas-react-color-text);\n}\n.canvas-react-select-option-searching:hover,\n.canvas-react-select-option-searching.canvas-react-select-option-active {\n background: var(--canvas-react-color-bg-active);\n}\n.canvas-react-select-option-disabled {\n color: #9ca3af;\n cursor: not-allowed;\n}\n.canvas-react-select-option-highlight {\n color: var(--canvas-react-color-primary);\n font-weight: 600;\n}\n.canvas-react-select-option-disabled .canvas-react-select-option-highlight {\n color: inherit;\n}\n.canvas-react-select-empty {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n padding: 0 11px;\n color: #9ca3af;\n font-size: var(--canvas-react-font-size);\n}\n');
718
738
  var ReactSelect = React.forwardRef(
719
739
  function ReactSelect2(props, ref) {
720
740
  const {
@@ -7239,6 +7259,333 @@ function clamp3(value, min, max) {
7239
7259
  }
7240
7260
  return Math.min(Math.max(value, min), max);
7241
7261
  }
7262
+
7263
+ // src/components/cascader/style.css
7264
+ styleInject('@import "../../styles/variables.css";\n.canvas-react-cascader {\n width: 100%;\n min-width: 0;\n}\n.canvas-react-cascader > .canvas-react-input-affix-wrapper {\n width: 100%;\n}\n.canvas-react-cascader-menus {\n display: flex;\n max-width: calc(100vw - 24px);\n overflow: auto;\n color: var(--canvas-react-color-text);\n font-size: var(--canvas-react-font-size);\n}\n.canvas-react-cascader-menu {\n flex: 0 0 auto;\n min-width: 120px;\n max-width: 320px;\n max-height: min(256px, calc(100vh - 48px));\n overflow: auto;\n padding: 4px;\n}\n.canvas-react-cascader-menu + .canvas-react-cascader-menu {\n border-left: 1px solid var(--canvas-react-color-border);\n}\n.canvas-react-cascader-option {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 20px;\n padding: 5px 10px;\n line-height: 22px;\n border-radius: var(--canvas-react-radius-sm);\n cursor: pointer;\n white-space: nowrap;\n}\n.canvas-react-cascader-option[aria-selected=true] {\n color: var(--canvas-react-color-primary);\n background: var(--canvas-react-color-bg-active);\n}\n.canvas-react-cascader-option[data-active=true] {\n background: var(--canvas-react-color-bg-hover, #f5f5f5);\n}\n.canvas-react-cascader-option[aria-disabled=true] {\n opacity: 0.4;\n cursor: not-allowed;\n}\n.canvas-react-cascader-empty {\n padding: 8px 10px;\n color: var(--canvas-react-color-text-muted);\n}\n.canvas-react-cascader-chevron {\n width: 7px;\n height: 7px;\n flex: 0 0 auto;\n margin-left: 8px;\n border-top: 1.5px solid #9ca3af;\n border-right: 1.5px solid #9ca3af;\n transform: rotate(45deg);\n transform-origin: center;\n transition: transform 0.18s ease, border-color 0.18s ease;\n}\n.canvas-react-cascader-option:not([aria-disabled=true]):hover .canvas-react-cascader-chevron,\n.canvas-react-cascader-option[aria-selected=true] .canvas-react-cascader-chevron {\n border-color: #6b7280;\n transform: rotate(135deg);\n}\n');
7265
+ function resolvePath(options, value) {
7266
+ const path = [];
7267
+ for (const part of value) {
7268
+ const item = options.find((option) => option.value === part);
7269
+ if (!item) break;
7270
+ path.push(item);
7271
+ options = item.children ?? [];
7272
+ }
7273
+ return path;
7274
+ }
7275
+ var EMPTY_OPTIONS = [];
7276
+ var EMPTY_VALUE = [];
7277
+ function ReactCascader(props) {
7278
+ const {
7279
+ value = EMPTY_VALUE,
7280
+ options = EMPTY_OPTIONS,
7281
+ showSearch = false,
7282
+ changeOnSelect = false,
7283
+ expandTrigger = "click",
7284
+ displayRender,
7285
+ onChange,
7286
+ allowClear = true,
7287
+ disabled,
7288
+ readOnly,
7289
+ onFocus,
7290
+ onBlur,
7291
+ onClick,
7292
+ onKeyDown,
7293
+ ...inputProps
7294
+ } = props;
7295
+ const anchorRef = React.useRef(null);
7296
+ const inputRef = React.useRef(null);
7297
+ const popupRef = React.useRef(null);
7298
+ const popupId = React.useId();
7299
+ const selected = React.useMemo(() => resolvePath(options, value), [options, value]);
7300
+ const [path, setPath] = React.useState(selected);
7301
+ const [open, setOpen] = React.useState(false);
7302
+ const [keyword, setKeyword] = React.useState("");
7303
+ const [typing, setTyping] = React.useState(false);
7304
+ const [focus, setFocus] = React.useState({ column: 0, index: -1 });
7305
+ const interactive = !disabled && !readOnly;
7306
+ React.useEffect(() => {
7307
+ setPath(selected);
7308
+ }, [selected]);
7309
+ const labels = value.map(
7310
+ (part, index) => selected[index]?.label ?? String(part)
7311
+ );
7312
+ const text = displayRender?.(labels, selected) ?? labels.join(" / ");
7313
+ const columns = [options];
7314
+ for (const item of path) {
7315
+ if (!item.children?.length) break;
7316
+ columns.push(item.children);
7317
+ }
7318
+ const searching = showSearch && keyword.trim().length > 0;
7319
+ const results = React.useMemo(() => {
7320
+ if (!keyword.trim()) return [];
7321
+ const matches = [];
7322
+ const visit = (items, parents) => {
7323
+ for (const item of items) {
7324
+ if (item.disabled) continue;
7325
+ const next = [...parents, item];
7326
+ if ((!item.children?.length || changeOnSelect) && next.map((part) => part.label).join(" / ").toLocaleLowerCase().includes(keyword.trim().toLocaleLowerCase()))
7327
+ matches.push(next);
7328
+ if (item.children?.length) visit(item.children, next);
7329
+ }
7330
+ };
7331
+ visit(options, []);
7332
+ return matches;
7333
+ }, [options, keyword, changeOnSelect]);
7334
+ React.useEffect(() => {
7335
+ popupRef.current?.querySelector("[data-active='true']")?.scrollIntoView?.({ block: "nearest", inline: "nearest" });
7336
+ }, [focus, open]);
7337
+ const choose = (next, trigger, fromSearch = false) => {
7338
+ const item = next[next.length - 1];
7339
+ if (!item || next.some((option) => option.disabled)) return;
7340
+ setPath(next);
7341
+ const complete = !item.children?.length || fromSearch;
7342
+ if (complete || changeOnSelect)
7343
+ onChange?.(
7344
+ next.map((option) => option.value),
7345
+ next,
7346
+ { trigger, complete }
7347
+ );
7348
+ if (complete) {
7349
+ setOpen(false);
7350
+ setKeyword("");
7351
+ setTyping(false);
7352
+ }
7353
+ };
7354
+ const show = () => {
7355
+ if (!interactive) return;
7356
+ setOpen(true);
7357
+ setPath(selected);
7358
+ };
7359
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7360
+ "div",
7361
+ {
7362
+ ref: anchorRef,
7363
+ className: `canvas-react-cascader${open && interactive ? " canvas-react-cascader-open" : ""}`,
7364
+ children: [
7365
+ /* @__PURE__ */ jsxRuntime.jsx(
7366
+ ReactInput,
7367
+ {
7368
+ ref: inputRef,
7369
+ ...inputProps,
7370
+ disabled,
7371
+ readOnly: readOnly || !showSearch,
7372
+ allowClear: false,
7373
+ role: "combobox",
7374
+ "aria-haspopup": "listbox",
7375
+ "aria-expanded": open,
7376
+ "aria-controls": open ? popupId : void 0,
7377
+ "aria-activedescendant": open && focus.index >= 0 ? `${popupId}-${searching ? 0 : focus.column}-${focus.index}` : void 0,
7378
+ value: open && showSearch && typing ? keyword : text,
7379
+ onFocus: (event) => {
7380
+ show();
7381
+ onFocus?.(event);
7382
+ },
7383
+ onClick: (event) => {
7384
+ show();
7385
+ onClick?.(event);
7386
+ },
7387
+ onBlur: (event) => {
7388
+ setOpen(false);
7389
+ setKeyword("");
7390
+ setTyping(false);
7391
+ onBlur?.(event);
7392
+ },
7393
+ onChange: (event) => {
7394
+ setTyping(true);
7395
+ setKeyword(event.target.value);
7396
+ setOpen(true);
7397
+ setFocus({ column: 0, index: -1 });
7398
+ },
7399
+ onKeyDown: (event) => {
7400
+ onKeyDown?.(event);
7401
+ if (event.defaultPrevented || !interactive) return;
7402
+ if (event.key === "Escape") {
7403
+ event.preventDefault();
7404
+ setOpen(false);
7405
+ setKeyword("");
7406
+ setTyping(false);
7407
+ return;
7408
+ }
7409
+ if (![
7410
+ "ArrowDown",
7411
+ "ArrowUp",
7412
+ "ArrowRight",
7413
+ "ArrowLeft",
7414
+ "Enter"
7415
+ ].includes(event.key))
7416
+ return;
7417
+ event.preventDefault();
7418
+ setOpen(true);
7419
+ const column = searching ? 0 : Math.min(focus.column, columns.length - 1);
7420
+ const items = searching ? results.map((result) => result[result.length - 1]) : columns[column];
7421
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
7422
+ const direction = event.key === "ArrowDown" ? 1 : -1;
7423
+ let index = focus.index;
7424
+ if (index < 0) index = direction === 1 ? -1 : 0;
7425
+ for (let count = 0; count < items.length; count++) {
7426
+ index = (index + direction + items.length) % items.length;
7427
+ if (!items[index].disabled) {
7428
+ setFocus({ column, index });
7429
+ break;
7430
+ }
7431
+ }
7432
+ } else if (event.key === "ArrowLeft" && !searching) {
7433
+ const previous = Math.max(0, column - 1);
7434
+ setFocus({
7435
+ column: previous,
7436
+ index: columns[previous].indexOf(path[previous])
7437
+ });
7438
+ } else {
7439
+ const item = items[focus.index];
7440
+ if (!item || item.disabled) return;
7441
+ const next = searching ? results[focus.index] : [...path.slice(0, column), item];
7442
+ if (event.key === "Enter") choose(next, "keyboard", searching);
7443
+ else if (event.key !== "ArrowRight") return;
7444
+ if (!searching && item.children?.length) {
7445
+ setPath(next);
7446
+ setFocus({
7447
+ column: column + 1,
7448
+ index: item.children.findIndex((child) => !child.disabled)
7449
+ });
7450
+ }
7451
+ }
7452
+ },
7453
+ suffix: /* @__PURE__ */ jsxRuntime.jsxs(
7454
+ "span",
7455
+ {
7456
+ className: `canvas-react-select-actions${allowClear && interactive && value.length > 0 ? " canvas-react-select-actions-clearable" : ""}`,
7457
+ onPointerDown: (event) => {
7458
+ if (!interactive) return;
7459
+ event.preventDefault();
7460
+ event.stopPropagation();
7461
+ },
7462
+ onMouseDown: (event) => {
7463
+ if (!interactive) return;
7464
+ event.preventDefault();
7465
+ event.stopPropagation();
7466
+ },
7467
+ onClick: (event) => {
7468
+ if (!interactive) return;
7469
+ event.stopPropagation();
7470
+ inputRef.current?.focus({ preventScroll: true });
7471
+ show();
7472
+ },
7473
+ children: [
7474
+ allowClear && interactive && value.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
7475
+ "button",
7476
+ {
7477
+ type: "button",
7478
+ className: "canvas-react-select-clear",
7479
+ tabIndex: -1,
7480
+ "aria-label": "\u6E05\u7A7A\u7EA7\u8054\u9009\u62E9",
7481
+ onPointerDown: (event) => {
7482
+ event.preventDefault();
7483
+ event.stopPropagation();
7484
+ },
7485
+ onMouseDown: (event) => {
7486
+ event.preventDefault();
7487
+ event.stopPropagation();
7488
+ },
7489
+ onClick: (event) => {
7490
+ event.preventDefault();
7491
+ event.stopPropagation();
7492
+ inputRef.current?.focus({ preventScroll: true });
7493
+ setKeyword("");
7494
+ setTyping(false);
7495
+ setPath([]);
7496
+ setFocus({ column: 0, index: -1 });
7497
+ setOpen(true);
7498
+ onChange?.([], [], { trigger: "clear", complete: false });
7499
+ },
7500
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7501
+ "span",
7502
+ {
7503
+ className: "canvas-react-select-clear-icon",
7504
+ "aria-hidden": "true"
7505
+ }
7506
+ )
7507
+ }
7508
+ ) : null,
7509
+ /* @__PURE__ */ jsxRuntime.jsx(
7510
+ "span",
7511
+ {
7512
+ className: `canvas-react-select-arrow${open && interactive ? " canvas-react-select-arrow-open" : ""}`,
7513
+ "aria-hidden": "true"
7514
+ }
7515
+ )
7516
+ ]
7517
+ }
7518
+ )
7519
+ }
7520
+ ),
7521
+ /* @__PURE__ */ jsxRuntime.jsx(
7522
+ ReactPopup,
7523
+ {
7524
+ constrainHeight: true,
7525
+ open: open && interactive,
7526
+ anchorRef,
7527
+ onOpenChange: setOpen,
7528
+ surfaceClassName: "canvas-react-cascader-popup",
7529
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7530
+ "div",
7531
+ {
7532
+ ref: popupRef,
7533
+ id: popupId,
7534
+ className: "canvas-react-cascader-menus",
7535
+ children: (searching ? [results.map((result) => result[result.length - 1])] : columns).map((items, column) => /* @__PURE__ */ jsxRuntime.jsx(
7536
+ "div",
7537
+ {
7538
+ role: "listbox",
7539
+ "aria-label": searching ? "\u641C\u7D22\u7ED3\u679C" : `\u7B2C ${column + 1} \u7EA7\u9009\u9879`,
7540
+ className: "canvas-react-cascader-menu",
7541
+ children: items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "canvas-react-cascader-empty", children: "\u6682\u65E0\u6570\u636E" }) : items.map((item, index) => {
7542
+ const next = searching ? results[index] : [...path.slice(0, column), item];
7543
+ const active = focus.column === column && focus.index === index;
7544
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7545
+ "div",
7546
+ {
7547
+ id: `${popupId}-${column}-${index}`,
7548
+ role: "option",
7549
+ "aria-selected": path[column] === item,
7550
+ "aria-disabled": !!item.disabled,
7551
+ "data-active": active,
7552
+ className: "canvas-react-cascader-option",
7553
+ onMouseDown: (event) => event.preventDefault(),
7554
+ onMouseEnter: () => {
7555
+ if (item.disabled) return;
7556
+ setFocus({ column, index });
7557
+ if (expandTrigger === "hover" && !searching && item.children?.length)
7558
+ setPath(next);
7559
+ },
7560
+ onClick: () => {
7561
+ setFocus({ column, index });
7562
+ choose(next, "mouse", searching);
7563
+ },
7564
+ children: [
7565
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: searching ? next.map((part) => part.label).join(" / ") : item.label }),
7566
+ !searching && item.children?.length ? /* @__PURE__ */ jsxRuntime.jsx(
7567
+ "span",
7568
+ {
7569
+ className: "canvas-react-cascader-chevron",
7570
+ "aria-hidden": "true"
7571
+ }
7572
+ ) : null
7573
+ ]
7574
+ },
7575
+ index
7576
+ );
7577
+ })
7578
+ },
7579
+ column
7580
+ ))
7581
+ }
7582
+ )
7583
+ }
7584
+ )
7585
+ ]
7586
+ }
7587
+ );
7588
+ }
7242
7589
  var ReactAutoComplete = React.forwardRef(function ReactAutoComplete2(props, ref) {
7243
7590
  const {
7244
7591
  onChange,
@@ -8529,6 +8876,7 @@ var reactMessage = {
8529
8876
  exports.REACT_COMPONENT_PREFIX = REACT_COMPONENT_PREFIX;
8530
8877
  exports.ReactAutoComplete = ReactAutoComplete;
8531
8878
  exports.ReactButton = ReactButton;
8879
+ exports.ReactCascader = ReactCascader;
8532
8880
  exports.ReactCheckbox = ReactCheckbox;
8533
8881
  exports.ReactCol = ReactCol;
8534
8882
  exports.ReactColorPicker = ReactColorPicker;