import * as React from 'react' import {__, _x} from '@wordpress/i18n' import cx from 'classnames' import { useReducer, } from '@wordpress/element' import { Button, Modal, __experimentalHStack as HStack, } from '@wordpress/components' import { hasBlockSupport, getBlockSupport, // @ts-expect-error } from '@wordpress/blocks' import { addFilter, applyFilters, } from '@wordpress/hooks' import { InspectorControls, // @ts-expect-error } from '@wordpress/block-editor' import { fullscreen, } from '@wordpress/icons' import { useDispatch, } from '@wordpress/data' import { createHigherOrderComponent, useCopyToClipboard, } from '@wordpress/compose' import { store as noticesStore, } from '@wordpress/notices' import { CopyIcon, } from '@ska/components' import { SkaPanelBody, } from '@ska/plugin' import { ARRAY_UNIQUE, htmlAttributeToReactAttribute, styleToReactObject, } from '@ska/utils' import { RecordEditor, } from '../components' import { useAs, } from './as' import { useHasPermissions, } from '../plugins/permissions' import type { tBlockAttributes, tBlockEditProps, tBlockNameOrType, tBlockSaveProps, tBlockType, } from '@ska/shared' export interface AttributesValue { record?: Record } export interface AttributesAttributes { skaBlocksAttributes?: AttributesValue } export const ATTRIBUTES_SUPPORT_KEY = 'skaBlocksAttributes' export const ATTRIBUTES_SUPPORT_DEFAULT_ENABLED = false export const hasAttributesSupport = (block: tBlockNameOrType) => hasBlockSupport(block, ATTRIBUTES_SUPPORT_KEY, ATTRIBUTES_SUPPORT_DEFAULT_ENABLED) /** * Default value can be provided in block `supports` attribute. * * @example * ```json * "supports": { * "skaBlocksAttributes": { * "aria-label": "Text" * } * } * ``` */ const getDefaultValue = (block: tBlockType) => { const support = getBlockSupport(block, ATTRIBUTES_SUPPORT_KEY, ATTRIBUTES_SUPPORT_DEFAULT_ENABLED) return { ...(typeof support === 'object' && { record: { ...support, }, }), } } const withCustomAttributes = (settings: tBlockType) => { if(!hasAttributesSupport(settings)) { return settings } if(!settings.attributes.skaBlocksAttributes) { const defaultValue = getDefaultValue(settings) Object.assign(settings.attributes, { skaBlocksAttributes: { type: 'object', ...(Object.keys(defaultValue).length > 0 && { default: defaultValue, }), }, }) } return settings } export const CLIPBOARD_PREFIX = 'ska-blocks-attributes:' const AttributesInspectorControls: React.FC> = (props) => { const [isFullscreen, toggleFullscreen] = useReducer((isActive) => !isActive, false) const { attributes, setAttributes, } = props const { skaBlocksAttributes = {}, } = attributes const { record = {}, } = skaBlocksAttributes const { createSuccessNotice, createErrorNotice, } = useDispatch(noticesStore) const copyRef = useCopyToClipboard( () => `${CLIPBOARD_PREFIX}${JSON.stringify(skaBlocksAttributes)}`, () => createSuccessNotice(__('Copied attributes to clipboard.', 'ska-blocks'), {type: 'snackbar'}) ) const applyPastedAttributes = (text: string) => { const invalidError = () => createErrorNotice(__('Invalid attributes.', 'ska-blocks'), {type: 'snackbar'}) if(text.indexOf(CLIPBOARD_PREFIX) !== 0) { invalidError() return } let attributes: AttributesValue = {} try { attributes = JSON.parse(text.replace(CLIPBOARD_PREFIX, '')) } catch(e) { invalidError() return } const { record = {}, ...rest } = attributes if(!Object.keys(record).length) { invalidError() return } setAttributes({ skaBlocksAttributes: { record: { ...skaBlocksAttributes.record, ...record, }, ...rest, }, }) createSuccessNotice(__('Pasted attributes.', 'ska-blocks'), {type: 'snackbar'}) } const onPaste = (e: React.ClipboardEvent) => { const text = e?.clipboardData?.getData('Text') if(!text || text.indexOf(CLIPBOARD_PREFIX) !== 0) { return } e.preventDefault() applyPastedAttributes(text) } if(!useHasPermissions()) { return null } return <> 0} skaIcon >

{__('Custom HTML attributes for the block root element.', 'ska-blocks')}