"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = exports.BlockBindingsPanel = void 0;
var _i18n = require("@wordpress/i18n");
var _blocks = require("@wordpress/blocks");
var _components = require("@wordpress/components");
var _data = require("@wordpress/data");
var _element = require("@wordpress/element");
var _compose = require("@wordpress/compose");
var _useBindingsAttributes = require("../hooks/use-bindings-attributes");
var _lockUnlock = require("../lock-unlock");
var _inspectorControls = _interopRequireDefault(require("../components/inspector-controls"));
var _blockContext = _interopRequireDefault(require("../components/block-context"));
var _blockEdit = require("../components/block-edit");
var _blockBindings = require("../utils/block-bindings");
var _store = require("../store");
var _jsxRuntime = require("react/jsx-runtime");
/**
 * WordPress dependencies
 */

/**
 * Internal dependencies
 */

const {
  Menu
} = (0, _lockUnlock.unlock)(_components.privateApis);
const EMPTY_OBJECT = {};
const useToolsPanelDropdownMenuProps = () => {
  const isMobile = (0, _compose.useViewportMatch)('medium', '<');
  return !isMobile ? {
    popoverProps: {
      placement: 'left-start',
      // For non-mobile, inner sidebar width (248px) - button width (24px) - border (1px) + padding (16px) + spacing (20px)
      offset: 259
    }
  } : {};
};
function BlockBindingsPanelDropdown({
  fieldsList,
  attribute,
  binding
}) {
  const {
    clientId
  } = (0, _blockEdit.useBlockEditContext)();
  const registeredSources = (0, _blocks.getBlockBindingsSources)();
  const {
    updateBlockBindings
  } = (0, _blockBindings.useBlockBindingsUtils)();
  const currentKey = binding?.args?.key;
  const attributeType = (0, _data.useSelect)(select => {
    const {
      name: blockName
    } = select(_store.store).getBlock(clientId);
    const _attributeType = (0, _blocks.getBlockType)(blockName).attributes?.[attribute]?.type;
    return _attributeType === 'rich-text' ? 'string' : _attributeType;
  }, [clientId, attribute]);
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
    children: Object.entries(fieldsList).map(([name, fields], i) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(_element.Fragment, {
      children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(Menu.Group, {
        children: [Object.keys(fieldsList).length > 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(Menu.GroupLabel, {
          children: registeredSources[name].label
        }), Object.entries(fields).filter(([, args]) => args?.type === attributeType).map(([key, args]) => /*#__PURE__*/(0, _jsxRuntime.jsxs)(Menu.RadioItem, {
          onChange: () => updateBlockBindings({
            [attribute]: {
              source: name,
              args: {
                key
              }
            }
          }),
          name: attribute + '-binding',
          value: key,
          checked: key === currentKey,
          children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Menu.ItemLabel, {
            children: args?.label
          }), /*#__PURE__*/(0, _jsxRuntime.jsx)(Menu.ItemHelpText, {
            children: args?.value
          })]
        }, key))]
      }), i !== Object.keys(fieldsList).length - 1 && /*#__PURE__*/(0, _jsxRuntime.jsx)(Menu.Separator, {})]
    }, name))
  });
}
function BlockBindingsAttribute({
  attribute,
  binding,
  fieldsList
}) {
  const {
    source: sourceName,
    args
  } = binding || {};
  const sourceProps = (0, _blocks.getBlockBindingsSource)(sourceName);
  const isSourceInvalid = !sourceProps;
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalVStack, {
    className: "block-editor-bindings__item",
    spacing: 0,
    children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalText, {
      truncate: true,
      children: attribute
    }), !!binding && /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalText, {
      truncate: true,
      variant: !isSourceInvalid && 'muted',
      isDestructive: isSourceInvalid,
      children: isSourceInvalid ? (0, _i18n.__)('Invalid source') : fieldsList?.[sourceName]?.[args?.key]?.label || sourceProps?.label || sourceName
    })]
  });
}
function ReadOnlyBlockBindingsPanelItems({
  bindings,
  fieldsList
}) {
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
    children: Object.entries(bindings).map(([attribute, binding]) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalItem, {
      children: /*#__PURE__*/(0, _jsxRuntime.jsx)(BlockBindingsAttribute, {
        attribute: attribute,
        binding: binding,
        fieldsList: fieldsList
      })
    }, attribute))
  });
}
function EditableBlockBindingsPanelItems({
  attributes,
  bindings,
  fieldsList
}) {
  const {
    updateBlockBindings
  } = (0, _blockBindings.useBlockBindingsUtils)();
  const isMobile = (0, _compose.useViewportMatch)('medium', '<');
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
    children: attributes.map(attribute => {
      const binding = bindings[attribute];
      return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalToolsPanelItem, {
        hasValue: () => !!binding,
        label: attribute,
        onDeselect: () => {
          updateBlockBindings({
            [attribute]: undefined
          });
        },
        children: /*#__PURE__*/(0, _jsxRuntime.jsx)(Menu, {
          placement: isMobile ? 'bottom-start' : 'left-start',
          gutter: isMobile ? 8 : 36,
          trigger: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalItem, {
            children: /*#__PURE__*/(0, _jsxRuntime.jsx)(BlockBindingsAttribute, {
              attribute: attribute,
              binding: binding,
              fieldsList: fieldsList
            })
          }),
          children: /*#__PURE__*/(0, _jsxRuntime.jsx)(BlockBindingsPanelDropdown, {
            fieldsList: fieldsList,
            attribute: attribute,
            binding: binding
          })
        })
      }, attribute);
    })
  });
}
const BlockBindingsPanel = ({
  name: blockName,
  metadata
}) => {
  const blockContext = (0, _element.useContext)(_blockContext.default);
  const {
    removeAllBlockBindings
  } = (0, _blockBindings.useBlockBindingsUtils)();
  const bindableAttributes = (0, _useBindingsAttributes.getBindableAttributes)(blockName);
  const dropdownMenuProps = useToolsPanelDropdownMenuProps();

  // `useSelect` is used purposely here to ensure `getFieldsList`
  // is updated whenever there are updates in block context.
  // `source.getFieldsList` may also call a selector via `select`.
  const _fieldsList = {};
  const {
    fieldsList,
    canUpdateBlockBindings
  } = (0, _data.useSelect)(select => {
    if (!bindableAttributes || bindableAttributes.length === 0) {
      return EMPTY_OBJECT;
    }
    const registeredSources = (0, _blocks.getBlockBindingsSources)();
    Object.entries(registeredSources).forEach(([sourceName, {
      getFieldsList,
      usesContext
    }]) => {
      if (getFieldsList) {
        // Populate context.
        const context = {};
        if (usesContext?.length) {
          for (const key of usesContext) {
            context[key] = blockContext[key];
          }
        }
        const sourceList = getFieldsList({
          select,
          context
        });
        // Only add source if the list is not empty.
        if (Object.keys(sourceList || {}).length) {
          _fieldsList[sourceName] = {
            ...sourceList
          };
        }
      }
    });
    return {
      fieldsList: Object.values(_fieldsList).length > 0 ? _fieldsList : EMPTY_OBJECT,
      canUpdateBlockBindings: select(_store.store).getSettings().canUpdateBlockBindings
    };
  }, [blockContext, bindableAttributes]);
  // Return early if there are no bindable attributes.
  if (!bindableAttributes || bindableAttributes.length === 0) {
    return null;
  }
  // Filter bindings to only show bindable attributes and remove pattern overrides.
  const {
    bindings
  } = metadata || {};
  const filteredBindings = {
    ...bindings
  };
  Object.keys(filteredBindings).forEach(key => {
    if (!(0, _useBindingsAttributes.canBindAttribute)(blockName, key) || filteredBindings[key].source === 'core/pattern-overrides') {
      delete filteredBindings[key];
    }
  });

  // Lock the UI when the user can't update bindings or there are no fields to connect to.
  const readOnly = !canUpdateBlockBindings || !Object.keys(fieldsList).length;
  if (readOnly && Object.keys(filteredBindings).length === 0) {
    return null;
  }
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_inspectorControls.default, {
    group: "bindings",
    children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_components.__experimentalToolsPanel, {
      label: (0, _i18n.__)('Attributes'),
      resetAll: () => {
        removeAllBlockBindings();
      },
      dropdownMenuProps: dropdownMenuProps,
      className: "block-editor-bindings__panel",
      children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalItemGroup, {
        isBordered: true,
        isSeparated: true,
        children: readOnly ? /*#__PURE__*/(0, _jsxRuntime.jsx)(ReadOnlyBlockBindingsPanelItems, {
          bindings: filteredBindings,
          fieldsList: fieldsList
        }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(EditableBlockBindingsPanelItems, {
          attributes: bindableAttributes,
          bindings: filteredBindings,
          fieldsList: fieldsList
        })
      }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalItemGroup, {
        children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.__experimentalText, {
          variant: "muted",
          children: (0, _i18n.__)('Attributes connected to custom fields or other dynamic data.')
        })
      })]
    })
  });
};
exports.BlockBindingsPanel = BlockBindingsPanel;
var _default = exports.default = {
  edit: BlockBindingsPanel,
  attributeKeys: ['metadata'],
  hasSupport() {
    return true;
  }
};
//# sourceMappingURL=block-bindings.js.map