Sage 10 + Poet block - Not loading

I am trying to add a line block using Poet in Sage 10. Already made one with @wordpress/create-block but wan tot add one to my theme using Poet.

So added package and tried following GitHub - Log1x/poet: Configuration-based post type, taxonomy, block category, and block registration for Sage 10. .

In wp-content/themes/cafejp/config/poet.php I have

...
'block' => [
        'cafejp/line' => [
            'attributes' => [
                'thickness' => [
                    'default' => '1.5',
                    'type' => 'number',
                ],
                'color' => [
                    'default' => '#e0bd5f',
                    'type' => 'string',
                ],
                'width' => [
                    'default' => '120%',
                    'type' => 'string',
                ],
                'borderStyle' => [
                    'default' => 'solid',
                    'type' => 'string',
                ],
            ],
        ],
    ],
...

The blade view is wp-content/themes/cafejp/resources/views/blocks/line.blade.php with

<div class="wp-block-line {{ $data->className ?? '' }}">
    <hr
        class="custom-line-block"
        style="
            border-top: {{ $data->thickness ?? '1.5' }}px 
            {{ $data->borderStyle ?? 'solid' }} 
            {{ $data->color ?? '#e0bd5f' }}
            width: {{ $data->width ?? '120%' }}
        "
    />
</div>

When I however look for the block in the editor post yarn build and wp acorn view:clear I see no blocks. The block only has the html mentioned and is based on edit.js:

...
<div {...useBlockProps()}>
	<hr
		className="custom-line-block"
		style={{
			borderTop: `${thickness}px ${borderStyle} ${color || '#e0bd5f'}`,
			width: width,
		}}
	/>
</div>
...

So what am I missing here that prevents a proper display still?

To add edit.js, save.js, index.js and view.js as well as block.json I added them this way

wp-content/themes/cafejp/
├── resources/
│   ├── scripts/
│   │   ├── blocks/
│   │   │   ├── line/
│   │   │   │   ├── block.json
│   │   │   │   ├── index.js
│   │   │   │   ├── edit.js
│   │   │   │   ├── save.js
│   ├── views/
│   │   ├── blocks/
│   │   │   ├── line.blade.php
├── config/
│   ├── poet.php

with block.json:

{
	"$schema": "https://schemas.wp.org/trunk/block.json",
	"apiVersion": 3,
	"name": "cafejp/line",
	"version": "0.1.0",
	"title": "Line Block",
	"category": "design",
	"icon": "minus",
	"description": "A block that adds a customizable line.",
	"example": {},
	"supports": {
		"html": false
	},
	"attributes": {
		"thickness": {
			"type": "number",
			"default": 1.5
		},
		"color": {
			"type": "string",
			"default": "#e0bd5f"
		},
		"width": {
			"type": "string",
			"default": "120%"
		},
		"borderStyle": {
			"type": "string",
			"default": "solid"
		}
	},
	"textdomain": "cafejp",
	"editorScript": "file:./index.js",
	"editorStyle": "file:./index.css",
	"style": "file:./style-index.css",
	"viewScript": "file:./view.js"
}

and edit.js:

/**
 * Retrieves the translation of text.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-i18n/
 */
import { __ } from '@wordpress/i18n';

/**
 * React hook that is used to mark the block wrapper element.
 * It provides all the necessary props like the class name.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops
 */
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, RangeControl, ColorPalette, TextControl, SelectControl } from '@wordpress/components';

/**
 * Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
 * Those files can contain any CSS code that gets applied to the editor.
 *
 * @see https://www.npmjs.com/package/@wordpress/scripts#using-css
 */
import './editor.scss';

/**
 * The edit function describes the structure of your block in the context of the
 * editor. This represents what the editor will render when the block is used.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit
 *
 * @return {Element} Element to render.
 */
export default function Edit({ attributes, setAttributes }) {
	const { thickness, color, width, borderStyle } = attributes;

	return (
		<>
			<InspectorControls>
				<PanelBody title={__('Line Settings', 'line-block')}>
					<RangeControl
						label={__('Thickness', 'line-block')}
						value={thickness}
						onChange={(value) => setAttributes({ thickness: value })}
						min={1}
						max={20}
					/>
					<ColorPalette
						value={color}
						onChange={(value) => setAttributes({ color: value || '#e0bd5f' })}
					/>
					<TextControl
						label={__('Width', 'line-block')}
						value={width}
						onChange={(value) => setAttributes({ width: value })}
						help={__('Set the width as a percentage or in pixels (e.g., 100% or 300px).')}
					/>
					<SelectControl
						label={__('Border Style', 'line-block')}
						value={borderStyle}
						options={[
							{ label: __('Solid', 'line-block'), value: 'solid' },
							{ label: __('Dotted', 'line-block'), value: 'dotted' },
							{ label: __('Dashed', 'line-block'), value: 'dashed' },
						]}
						onChange={(value) => setAttributes({ borderStyle: value })}
					/>
				</PanelBody>
			</InspectorControls>
			<div {...useBlockProps()}>
				<hr
					className="custom-line-block"
					style={{
						borderTop: `${thickness}px ${borderStyle} ${color || '#e0bd5f'}`,
						width: width,
					}}
				/>
			</div>
		</>
	);
}

and index.js:

/**
 * Registers a new block provided a unique name and an object defining its behavior.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
 */
import { registerBlockType } from '@wordpress/blocks';

/**
 * Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
 * All files containing `style` keyword are bundled together. The code used
 * gets applied both to the front of your site and to the editor.
 *
 * @see https://www.npmjs.com/package/@wordpress/scripts#using-css
 */
import './style.scss';

/**
 * Internal dependencies
 */
import Edit from './edit';
import save from './save';
import metadata from './block.json';

/**
 * Every block starts by registering a new block type definition.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
 */
registerBlockType( metadata.name, {
	/**
	 * @see ./edit.js
	 */
	edit: Edit,

	/**
	 * @see ./save.js
	 */
	save,
} );

as well as save.js:

/**
 * React hook that is used to mark the block wrapper element.
 * It provides all the necessary props like the class name.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops
 */
import { useBlockProps } from '@wordpress/block-editor';

/**
 * The save function defines the way in which the different attributes should
 * be combined into the final markup, which is then serialized by the block
 * editor into `post_content`.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#save
 *
 * @return {Element} Element to render.
 */
export default function save({ attributes }) {
	const { thickness, color, width, borderStyle } = attributes;

	return (
		<div {...useBlockProps.save()} className="wp-block-wpvillain-line-block">
			<hr
				className="custom-line-block"
				style={{
					borderTop: `${thickness}px ${borderStyle} ${color || '#e0bd5f'}`,
					width: width,
				}}
			/>
		</div>
	);
}

Assume I do not need registerBlockType . But still I do not see the block loaded.

Do still need to import these blocks into editor.js it seems reading an example editor js file from portalv6/web/app/themes/flexor/resources/scripts/editor.js at b47fcda0dd0efaa18e89616f533105d6734e4717 · idbsupport3F/portalv6 · GitHub and that does make sense.

/**
 * @see {@link https://bud.js.org/extensions/bud-preset-wordpress/editor-integration/filters}
 */
roots.register.filters('@scripts/filters');

/**
 * @see {@link https://webpack.js.org/api/hot-module-replacement/}
 */
if (import.meta.webpackHot) import.meta.webpackHot.accept(console.error);

/**
 * Accordian Block Register
 * 
 * @see {@link https://github.com/Log1x/poet/issues/22#issuecomment-792573232}
 */

import { __ } from '@wordpress/i18n'
import { registerBlockType } from '@wordpress/blocks'
import { registerIcons } from '@10up/block-components';

/**
 * React hook that is used to mark the block wrapper element.
 * It provides all the necessary props like the class name.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops
 */
import { InnerBlocks, useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';

/** components */
import images from './blocks/swiper-images'
import icons from './blocks/customIcon'
import testimonials from './blocks/testimonials'
import faq from './blocks/faq'
import link from './blocks/link'
import fixed from './blocks/fixed'
import { iconsPaths } from './helper/bootstrap-icons'

registerBlockType(`sage/swiperlogo`, {
    title: __(`Swiper Logo`, `sage`),
    category: `flexor`,
    icon: `format-gallery`,
    apiVersion: 3,
    supports: {
        className: false,
        color: {
            background: true
        },
        lock: false
    },
    edit: images
})

registerBlockType('sage/testimonials', {
    title: __('Testimonials', 'sage'),
    category: 'flexor',
    icon: 'format-quote',
    apiVersion: 3,
    supports: {
        lock: false
    },
    edit: testimonials
})

registerBlockType('sage/icon', {
    title: __('Icon', 'sage'),
    category: 'flexor',
    icon: 'heart',
    apiVersion: 3,
    supports: {
        lock: false
    },
    edit: icons
})

registerBlockType('sage/faq', {
    title: __('FAQ', 'sage'),
    category: 'flexor',
    icon: 'info',
    apiVersion: 3,
    supports: {
        lock: false
    },
    edit: faq,
    save() {
        return <InnerBlocks.Content/>
    }
})

registerBlockType('sage/link', {
    title: __('Link Container', 'sage'),
    category: 'flexor',
    icon: 'admin-links',
    apiVersion: 3,
    supports: {
        lock: false,
        color: {
            text: false,
            gradients: true
        },
        background: {
            backgroundImage: true, // Enable background image control.
            backgroundSize: true // Enable background image + size control.
        },
        shadow: true, // Enable the box-shadow picker.
        spacing: {
            margin: true,  // Enable margin UI control.
            padding: true, // Enable padding UI control.
        }
    },
    edit: link,
    save({attributes}) {
        const { link, newTab, text, border, borderRadius } = attributes;
        const blockProps = useBlockProps.save({
            className: "link-container-component",
            style: {
                border: border ? Object.values(border) : undefined,
                borderTopLeftRadius: borderRadius ? borderRadius.left : undefined,
                borderTopRightRadius: borderRadius ? borderRadius.top : undefined,
                borderBottomLeftRadius: borderRadius ? borderRadius.bottom : undefined,
                borderBottomRightRadius: borderRadius ? borderRadius.right : undefined,
                overflow: 'hidden'
            }
        });
        const innerBlocksProps = useInnerBlocksProps.save(blockProps);

        return <a href={(link && link.length > 0) ? link : null } target={newTab ? '_blank' : null} rel={newTab ? 'noopener' : null} title={text ? __(text, 'sage') : null} {...innerBlocksProps} />;
    }
})

registerBlockType('sage/fixed', {
    title: __('Fixed Container', 'sage'),
    category: 'flexor',
    icon: 'editor-insertmore',
    apiVersion: 3,
    supports: {
        lock: false,
        color: {
            text: false,
            background: true,
            gradients: true
        },
        background: {
            backgroundImage: true, // Enable background image control.
            backgroundSize: true // Enable background image + size control.
        },
        align: true,
        dimensions: {
            aspectRatio: true, // Enable aspect ratio control.
            minHeight: true // Enable min height control.
        },
        spacing: {
            margin: true,  // Enable margin UI control.
            padding: true, // Enable padding UI control.
        }
    },
    edit: fixed,
    save() {
        const blockProps = useBlockProps.save();
        const innerBlocksProps = useInnerBlocksProps.save(blockProps);
        return <div {...innerBlocksProps} />;
    }
})

/**
 * Convert Case to any format available
 * @param {string} str 
 * @param {('camel' | 'kebab' | 'snake' | 'pascal' | 'sentence')} toCase 
 * @returns string
 * 
 * @see https://www.30secondsofcode.org/js/s/string-case-conversion/#:~:text=Kebab%20case%20is%20most%20often,join%20them%20with%20a%20hyphen.
 */
const convertCase = (str, toCase = 'camel') => {
    if (!str) return '';

    const delimiter =
        toCase === 'snake'
            ? '_'
            : toCase === 'kebab'
                ? '-'
                : ['title', 'sentence'].includes(toCase)
                    ? ' '
                    : '';

    const transform = ['camel', 'pascal'].includes(toCase)
        ? x => x.slice(0, 1).toUpperCase() + x.slice(1).toLowerCase()
        : ['snake', 'kebab'].includes(toCase)
            ? x => x.toLowerCase()
            : toCase === 'title'
                ? x => x.slice(0, 1).toUpperCase() + x.slice(1)
                : x => x;

    const finalTransform =
        toCase === 'camel'
            ? x => x.slice(0, 1).toLowerCase() + x.slice(1)
            : toCase === 'sentence'
                ? x => x.slice(0, 1).toUpperCase() + x.slice(1)
                : x => x;

    const words = str.match(
        /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g
    );

    return finalTransform(words.map(transform).join(delimiter));
};


const SVGJSON = function(iconsObj) {

    const icons = [];

    const setIcons = function(obj) {
        var name = convertCase(obj.name, 'kebab');
        var label = convertCase(obj.name, 'sentence');
        if(obj.paths.length > 0) {
            var pathSVG = obj.paths.map((path, i) => {
                var svg = document.createElement('path');
                Object.keys(path).forEach((currentVal) => {
                    svg.setAttribute(currentVal, path[currentVal])
                })
                return svg.outerHTML;
            }).join(' ');
        }
        var source = `<svg fill="${obj.fill}" viewBox="${obj.viewBox}" height="16" width="16" xmlns="https://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" style="width:100%;height:100%;">${pathSVG}</svg>`

        return {
            source,
            name,
            label
        }
    }

    for (const property in iconsObj){
        icons.push(setIcons(iconsObj[property]));
    }

    return icons;
}


/**
 * Icon Set Configurations
 * 
 * @see https://github.com/Machacek76/svg-to-json
 * @see https://github.com/10up/block-components/tree/develop/api/register-icons
 */
registerIcons({
    name: 'sage/bootstrap-icons',
    label: "Bootstrap Icons",
    icons: SVGJSON(iconsPaths)
});

updated wp-content/themes/cafejp/resources/scripts/editor.js with call to line block:

/**
 * @see {@link https://bud.js.org/extensions/bud-preset-wordpress/editor-integration/filters}
 */
roots.register.filters('@scripts/filters');

/**
 * @see {@link https://webpack.js.org/api/hot-module-replacement/}
 */
if (import.meta.webpackHot) import.meta.webpackHot.accept(console.error);

import './blocks/line'; // Import the line block

Also added missing style.scss, editor.scss . Getting things to load now. And that with line.blade.view

<div class="wp-block-line {{ $data->className ?? '' }}">
    <hr
        class="custom-line-block"
        style="
            border-top: {{ $data->thickness ?? '1.5' }}px 
            {{ $data->borderStyle ?? 'solid' }} 
            {{ $data->color ?? '#e0bd5f' }};
            width: {{ $data->width ?? '120%' }};
        "
    />
</div>

but not sure I need the view … I have all in JS already… But somehow styling is off in a stack block. And I did see the view is being used. Just not all styling applied. Color is off still.

Did it with a Bud based setup in the end. Structure was setup this way

wp-content/themes/cafejp/
├── resources/
│   ├── scripts/
│   │   ├── blocks/
│   │   │   ├── line/
│   │   │   │   ├── line.block.js     // Your block registration file
│   │   │   │   ├── edit.js           // Block edit component
│   │   │   │   ├── save.js           // Block save component
│   │   │   │   ├── style.scss        // Block styles
│   │   │   │   ├── block.json        // Block metadata
│   │   ├── editor.js

So a wp-content/themes/cafejp/resources/scripts/editor.js with

    /**
     * @see {@link https://bud.js.org/extensions/bud-preset-wordpress/editor-integration/filters}
     */
    roots.register.filters('@scripts/filters');
    roots.register.blocks('@scripts/blocks');

    /**
     * @see {@link https://webpack.js.org/api/hot-module-replacement/}
     */
    if (import.meta.webpackHot) import.meta.webpackHot.accept(console.error);

and a wp-content/themes/cafejp/resources/scripts/blocks/line/line.block.js with

import { registerBlockType } from '@wordpress/blocks';
import edit from './edit';
import save from './save';
import metadata from './block.json';

// Import block styles
import './style.scss';

registerBlockType(metadata.name, {
    ...metadata,
    edit,
    save,
});

only in wp-content/themes/cafejp/resources/scripts/blocks/line/save.js I had to add style"with=100%":

/**
 * React hook that is used to mark the block wrapper element.
 * It provides all the necessary props like the class name.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops
 */
import { useBlockProps } from '@wordpress/block-editor';

/**
 * The save function defines the way in which the different attributes should
 * be combined into the final markup, which is then serialized by the block
 * editor into `post_content`.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#save
 *
 * @return {Element} Element to render.
 */
export default function save({ attributes }) {
	const { thickness, color, width, borderStyle } = attributes;

	return (
		<div style="width:100%;" {...useBlockProps.save()}>
			<hr
				className="custom-line-block"
				style={{
					borderTop: `${thickness}px ${borderStyle || 'solid'} ${color || '#e0bd5f'}`,
					width: width || '100%',
				}}
			/>
		</div>
	);
}

because the style added to wp-content/themes/cafejp/resources/scripts/blocks/line/style.scss for it:

/**
 * The following styles get applied both on the front of your site
 * and in the editor.
 *
 * Replace them with your own styles or remove the file completely.
 */

 .wp-block-wpvillain-line-block {
	width: 100%;
}

would never get applied. And that would cause the line to collapse frontend and not display. Perhaps something to do with the way Bud and Bud Sass builds stuff. If anyone has ideas on that I am all ears.