{"version":3,"file":"templateEditorPalette.mjs","names":[],"sources":["../../../../package/common/templateEditor/templateEditorPalette.tsx"],"sourcesContent":["import { useId, useMemo, useRef, useState } from 'react';\nimport cx from 'classnames';\n\nimport styles from './templateEditor.module.pcss';\nimport { isSelfActivation } from '../utils/activationKey';\nimport { toneProps } from '../styles/tone';\nimport { ThemeColor } from '../themeProvider/color.types';\nimport { flattenTokens, tokenLabel } from './templateEditor.utils';\nimport { TemplateEditorPalettePosition, type TemplateEditorPaletteProps } from './templateEditor.types';\n\nconst TONE = toneProps(ThemeColor.Primary).className;\nconst DISABLED_TONE = toneProps(ThemeColor.Neutral).className;\n\n/**\n * The list of insertable placeholders. Every entry is reachable three ways: by\n * dragging it into the text, by clicking it, and by tabbing into the toolbar\n * and pressing Enter. Drag alone would be unusable with a keyboard and impossible\n * on touch, where HTML5 drag events never fire.\n */\nfunction TemplateEditorPalette({\n  groups,\n  label,\n  labels,\n  position,\n  prefix,\n  suffix,\n  disabled = false,\n  dragRef,\n  onInsert,\n  onHighlight,\n  classNames,\n  styles: slotStyles,\n}: TemplateEditorPaletteProps) {\n  const groupIdBase = useId();\n  const [activeIndex, setActiveIndex] = useState(0);\n  const itemRefs = useRef<(HTMLDivElement | null)[]>([]);\n  const tokens = useMemo(() => flattenTokens(groups), [groups]);\n  // Roving tabindex needs each item's position in the flattened list, which the\n  // grouped markup cannot count on its own without mutating a render-scope variable.\n  const indexById = useMemo(() => new Map(tokens.map((token, index) => [token.id, index])), [tokens]);\n  const enabled = useMemo(\n    () => (disabled ? [] : tokens.flatMap((token, index) => (token.disabled ? [] : [index]))),\n    [disabled, tokens],\n  );\n  // Falls back to the first enabled entry, or a disabled first token, or one\n  // disabled since it was last focused, would take the palette out of the tab order.\n  const tabStop = enabled.includes(activeIndex) ? activeIndex : enabled[0];\n  const horizontal = position === TemplateEditorPalettePosition.Bottom;\n\n  function focusEnabled(slot: number) {\n    const index = enabled[Math.max(0, Math.min(enabled.length - 1, slot))];\n    if (index === undefined) return;\n    setActiveIndex(index);\n    itemRefs.current[index]?.focus();\n  }\n\n  function handleKeyDown(event: React.KeyboardEvent, index: number, tokenId: string) {\n    const at = enabled.indexOf(index);\n    if (event.key === (horizontal ? 'ArrowRight' : 'ArrowDown') || event.key === 'ArrowDown') {\n      event.preventDefault();\n      focusEnabled(at + 1);\n      return;\n    }\n    if (event.key === (horizontal ? 'ArrowLeft' : 'ArrowUp') || event.key === 'ArrowUp') {\n      event.preventDefault();\n      focusEnabled(at - 1);\n      return;\n    }\n    if (event.key === 'Home') {\n      event.preventDefault();\n      focusEnabled(0);\n      return;\n    }\n    if (event.key === 'End') {\n      event.preventDefault();\n      focusEnabled(enabled.length - 1);\n      return;\n    }\n    if (isSelfActivation(event)) {\n      event.preventDefault();\n      if (at >= 0) onInsert(tokenId);\n    }\n  }\n\n  return (\n    <div className={cx(styles.templateEditorPalette, classNames?.palette)} style={slotStyles?.palette}>\n      {label && (\n        <div\n          className={cx(styles.templateEditorPaletteLabel, classNames?.paletteLabel)}\n          style={slotStyles?.paletteLabel}\n        >\n          {label}\n        </div>\n      )}\n      <div\n        role='toolbar'\n        aria-label={label ?? labels.palette}\n        aria-orientation={horizontal ? 'horizontal' : 'vertical'}\n        className={styles.templateEditorPaletteList}\n      >\n        {groups.map((group, groupIndex) => (\n          <div\n            key={group.id ?? group.label ?? groupIndex}\n            role='group'\n            aria-labelledby={group.label ? `${groupIdBase}-${groupIndex}` : undefined}\n            className={cx(styles.templateEditorPaletteGroup, classNames?.paletteGroup)}\n            style={slotStyles?.paletteGroup}\n          >\n            {group.label && (\n              <div\n                id={`${groupIdBase}-${groupIndex}`}\n                className={cx(styles.templateEditorPaletteGroupLabel, classNames?.paletteGroupLabel)}\n                style={slotStyles?.paletteGroupLabel}\n              >\n                {group.label}\n              </div>\n            )}\n            <div className={styles.templateEditorPaletteItems}>\n              {group.tokens.map((token) => {\n                const index = indexById.get(token.id) ?? 0;\n                const isDisabled = !!token.disabled || disabled;\n                return (\n                  <div\n                    key={token.id}\n                    ref={(node) => {\n                      itemRefs.current[index] = node;\n                    }}\n                    role='button'\n                    aria-disabled={isDisabled || undefined}\n                    tabIndex={isDisabled ? undefined : index === tabStop ? 0 : -1}\n                    draggable={!isDisabled}\n                    className={cx(\n                      isDisabled ? DISABLED_TONE : TONE,\n                      styles.templateEditorChip,\n                      styles.templateEditorPaletteItem,\n                      isDisabled && styles.templateEditorPaletteItemDisabled,\n                      classNames?.paletteItem,\n                    )}\n                    style={slotStyles?.paletteItem}\n                    // Deliberately no `preventDefault` on mousedown here. It would\n                    // hold the editable's selection, but Blink and Gecko treat a\n                    // prevented mousedown as \"no drag\", so `dragstart` would never\n                    // fire and the whole drag path would silently do nothing. The\n                    // caret is recovered from the editable's last known selection\n                    // instead, which survives the blur this causes.\n                    onFocus={() => {\n                      setActiveIndex(index);\n                      onHighlight(token.id);\n                    }}\n                    onBlur={() => onHighlight(null)}\n                    onMouseEnter={() => onHighlight(token.id)}\n                    onMouseLeave={() => onHighlight(null)}\n                    onClick={() => !isDisabled && onInsert(token.id)}\n                    onKeyDown={(event) => handleKeyDown(event, index, token.id)}\n                    onDragStart={(event) => {\n                      if (isDisabled) {\n                        event.preventDefault();\n                        return;\n                      }\n                      dragRef.current = { kind: 'insert', id: token.id };\n                      // The serialized placeholder, not the bare id: a drop into a\n                      // *different* editor never sees this palette's drag ref, so it\n                      // falls back to this text, which the target parses into a chip.\n                      // It is also the useful thing to receive in any other app.\n                      event.dataTransfer.setData('text/plain', prefix + token.id + suffix);\n                      event.dataTransfer.effectAllowed = 'copy';\n                    }}\n                    onDragEnd={() => {\n                      dragRef.current = null;\n                    }}\n                  >\n                    <span className={styles.templateEditorPaletteItemLabel}>{tokenLabel(token)}</span>\n                    {token.description && (\n                      <span className={styles.templateEditorPaletteItemDescription}>{token.description}</span>\n                    )}\n                  </div>\n                );\n              })}\n            </div>\n          </div>\n        ))}\n      </div>\n    </div>\n  );\n}\n\nexport default TemplateEditorPalette;\n"],"mappings":"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"}