♠
Page No.1
ブロックエディタでテーブルなんぞを作っている時に、そういえば css grid は標準で使えないのだろうか?などとふと思った。ちょっとやってみたところ、グループボックス等で flex はできたけれど grid は見当たらなかった。ネットでうろうろしてみたが、出くわすのはプラグインを使う情報ばかり。
え~!さくっと簡単に使えないの?って、しっかり調べたわけではないので、もしかしたら手軽な方法などあるのかもしれない。まぁ、でも、インナーブロックでインラインスタイルを設定できる自作ブロックがあるので、それを使えば別にどうってことなく、css グリッドレイアウトなるものは作れるだろうと。
まぁ、実際にやってみると、公開されているページのほうは、なんの問題もなく想定通りのグリッドレイアウトで表示される。しかるに、問題は管理画面における編集ページのほう、いわゆる Block Editor の画面においてである。早い話、こちらではまったくグリッドレイアウトでの表示にはならない。
原因はといえば、実に明解でシンプルである。インナーブロックを使ったブロックの場合、親要素にラッピングされた子要素としての innerblock があるのだけれど、エディタ画面においてはその innerblock 自体も二重の div ボックスによってラッピングされているのである。インラインスタイルが設定されるのは親要素であり、その直下にあるのは1つの div ボックスなので、その1つだけの div が対象となる grid レイアウトなどは、無意味にただ幅が狭くなってしまうだけのものとなってしまうのである。 こんな具合に。2、3行めが自動的に innerblock によって付加される div となる。
インナーブロックにおいて、自動的に付加される二重のラッパー div を取り除く方法はあるのだろうか?あれこれと探し回ってみたけれど、やはりというか、これはなかなか困難なことのようだ。ちなみに、標準装備のグループボックスで使える flex レイアウト。これ、flex を使うときには、エディタ画面においても、子要素をまとめるインナーブロックのラッパーは無くなる。このことからも出来なくはなさそうなのだけれど、なかなかややこしい部分なのではなかろうかと。
それがだめならと、エディタ画面においては、親ボックスに設定されるはずのインラインスタイル設定を、インナーブロックの内側のラッパーに設定できればグリッドレイアウトになるはずである。そのほうがよほど手っ取り早いしわかりやすい。ただし、アップデートの場合など、WordPress 側の都合でこれらの class 名を変更されてしまうと無意味になってしまう。レイアウトが反映されなくなったときは、まずそれを疑ってみればいいと。
上記 HTML を見ると、インナーブロックの外側のラッパーの class は「 block-editor-inner-blocks 」であり、内側の class は「 block-editor-block-list__layout 」であり、他の同じブロックを見ても共通しているので、これがセレクターとして使えそう。内側だけあれば良さそうであるけれど、例えば、子要素にまた innerblock を使ったブロックがあったりした場合、それらの要素にはスタイルが反映されないようにするには、親要素の直下の要素だけ、という指定をする必要があり、それには外側の class も必要になるとおもう。
親であるブロック本体の方は、同じブロックを複数使っている可能性を考慮すると、それぞれに違うスタイル設定をしている場合などは間違いなくあるはずで、そうなると class は使えないので、必然的に id を使わざるをえない。ただこれは、useBlockProps においてはデフォルトで id の文字列を持っているので、指定されていない場合はそれを使えばいいと。
React のベースは Javascript なので普通に Javascript で使えるものは動く。 スタイルの設定においては、ページ読み込み時には .sheet.insertRule を使うことにして、スタイル設定に影響のある要素の入力による更新があった場合は、普通に、document.element.style.cssText によってスタイルの更新をさせた。
.sheet.insertRule を使う必要性というのは、ページ読み込み時に既存のブロックにおいて、innerblock で付加される内側のラッパー div にたいしてスタイルを設定する方法が他に思いつかなかったから。エディタにおいてのみ読み込むスタイルシートを指定することは出来るけれど、それだと固定されたスタイル設定になってしまい、ブロックによって異なるスタイル設定を動的に指定することはできないと思う。
( function ( blocks, element, blockEditor, components ) {
const el = element. createElement,
Fragment = element. Fragment,
InspectorControls = blockEditor. InspectorControls,
TextControl = components. TextControl,
useBlockProps = blockEditor. useBlockProps,
InnerBlocks = blockEditor. InnerBlocks;
function treat_style ( val ) {
let tmpstyle = { } ;
if ( val ) {
let vary = val. split ( ';' ) ;
for ( let i = 0 , vcnt = vary. length ; i < vcnt; ++ i ) {
let tmp = [ ] ;
if ( vary[ i ] ) {
tmp[ 0 ] = vary[ i ] . substring ( 0 , vary[ i ] . indexOf ( ':' ) ) ;
tmp[ 1 ] = vary[ i ] . substring ( vary[ i ] . indexOf ( ':' ) + 1 ) ;
tmp[ 2 ] = tmp[ 0 ] . split ( '-' ) ;
if ( tmp[ 2 ] [ 1 ] ) {
let tmpstr = '' ;
for ( let j = 1 , tar_len = tmp[ 2 ] . length ; j < tar_len; ++ j ) {
tmpstr += tmp[ 2 ] [ j ] . slice ( 0 , 1 ) . toUpperCase ( ) + tmp[ 2 ] [ j] . slice ( 1 ) ;
}
tmp[ 2 ] [ 0 ] += tmpstr;
}
if ( tmp[ 1 ] ) {
tmpstyle[ tmp[ 2 ] [ 0 ] ] = tmp[ 1 ] ;
}
}
}
}
return tmpstyle;
}
let dynamicStyles = null ;
function addStyle ( cssstr ) {
if ( ! dynamicStyles ) {
const doc = document ;
if ( null === doc. getElementById ( 'stx-grid-id-styles' ) ) {
dynamicStyles = doc. createElement ( 'style' ) ;
dynamicStyles. id = 'stx-grid-id-styles' ;
document . head. appendChild ( dynamicStyles ) ;
}
}
dynamicStyles. sheet. insertRule ( cssstr, dynamicStyles. length ) ;
}
blocks. registerBlockType ( 'stx/grid-wrapper-id' , {
apiVersion : 2 ,
title : 'STX grid-wrapper-id' ,
icon : 'grid-view' ,
category : 'design' ,
description : 'id 及びインラインスタイルを指定でき、css grid で layout できるラッパー。デフォルトで付加されるclass, wp-block-stx-grid-wrapper によってエディタでは css grid layout となる。' ,
attributes : {
anchor : { type : 'string' } ,
styles : { type : 'string' , default : '' } ,
} ,
supports : {
anchor : true ,
} ,
edit : function ( props ) {
const blockProps = useBlockProps ( { className : props. attributes. className } ) ;
let styles = props. attributes. styles,
anchor = props. attributes. anchor,
elem = {
id : anchor ? anchor : blockProps. id,
} ,
editorgridchildstyle = '#' + ( anchor ? anchor : blockProps. id ) + ' > .block-editor-inner-blocks > .block-editor-block-list__layout{' + styles + '}' ;
addStyle ( editorgridchildstyle ) ;
let changeId = null ;
function styleChange ( value ) {
clearTimeout ( changeId ) ;
changeId = setTimeout ( ( ) => {
let styleval = 'display:block;' ;
if ( value ) {
styleval = value;
}
if ( ';' === styleval[ ( styleval. length - 1 ) ] ) {
if ( ! anchor ) {
anchor = blockProps. id;
}
const doc = document ;
if ( anchor ) {
if ( null !== doc. getElementById ( anchor ) ) {
const tarel = doc. getElementById ( anchor ) ,
tarchil = tarel. getElementsByClassName ( 'block-editor-block-list__layout' ) ;
if ( tarchil[ 0 ] ) {
tarchil[ 0 ] . style . cssText = styleval;
}
}
}
}
} , 1500 ) ;
}
return (
el (
Fragment,
null ,
el (
InspectorControls,
null ,
el ( 'div' , { id : 'stx_grdiv_sdbr' , style : { fontSize : '1.3em' } } ,
el (
TextControl,
{
label : 'styles' ,
help : 'div に設定するインラインスタイル。通常のcssに記述するスタイルで。最後に必ず ";" を付加する。eq. margin-left:10px;color:red;font-size:1.1em;' ,
value : styles,
onChange : function ( newValue ) { props. setAttributes ( { styles : newValue } ) ; styleChange ( newValue ) ; }
}
) ,
) ,
) ,
el (
'div' ,
Object . assign ( blockProps, elem ) ,
el ( InnerBlocks )
)
)
) ;
} ,
save : function ( props ) {
const blockProps = useBlockProps. save ( ) ;
if ( props. attributes. anchor ) {
blockProps. id = props. attributes. anchor;
}
if ( props. attributes. styles ) {
blockProps. style = treat_style ( props. attributes. styles ) ;
}
return el (
'div' ,
blockProps,
el ( InnerBlocks. Content )
) ;
} ,
} ) ;
} (
window . wp. blocks,
window . wp. element,
window . wp. blockEditor,
window . wp. components,
) ) ;
Copy Expand ‹ › ‹ › ‹ › ‹ › ‹ ›
実を言うと始め、このブロックの id属性 においては、ブロックが標準で備えている anchor の機能は使わず InspectorControls を使用して自前で装備した。と、いうのは、anchor を使用した場合の id を指定する文字列が更新されたときの、イベントの取得がなかなかにややこしいもので、よくわからなかったから。id が変更されたということは、スタイル設定の対象が変更されたということで、その都度、対応させたい訳である。その点、InspectorControls を使って自装すれば、その変更は onChange により実に簡単に対応できる。
その辺りの更新に際してのイベント処理も自装しなければいけないものだと思いこんでいたわけで。そして始めに作ったブロックが下のもの。これで id 変更時のスタイル設定の対象の変更もうまく動いていた。だがしかし、ちょっと待てよと!あれっ! id 変更に伴う処理は入れただろうかと、確認してみると、やはりというかまだその処理を加えてはいなかった。
下を見るとわかると思うけれど、edit の InspectorControls の部分、idstr の変更における onChange に登録してあるのは attributes の更新処理だけ。この状態で id の変更において、ちゃんと意図した結果が得られていたから不思議に思った。わざわざそのための処理を入れなくとも、attributes の変更により、それに紐付けられている .sheet.insertRule のスタイル設定も更新されるということか。それなら、と style の方も、その更新処理を入れなくてもいいのかも?と、試してみたところ、style の更新に関しては全く知らぬ顔だった。
同じくattributes の値であり、同じように変数で紐づけて .sheet.insertRule に設定しているのに id はよくて style はだめというのは、いったいどう違うというのだろうか。よくわからない。 と、まぁ、なんにしても id属性 のほうは変更に際しての更新処理をわざわざ入れなくても良さそうということで、それなら gutenberg が標準で備えてくれている anchor でも同じなのではと、ためしてみたら思ったとおりそれでもいけた。と、いうことで、わざわざその部分をあえて InspectorControls で自装する必要もなく anchor を使うことにした、ということである。ちなみに、もちろんのこと、下のブロックもちゃんと機能する。
( function ( blocks, element, blockEditor, components ) {
const el = element. createElement,
Fragment = element. Fragment,
InspectorControls = blockEditor. InspectorControls,
TextControl = components. TextControl,
SelectControl = components. SelectControl,
useBlockProps = blockEditor. useBlockProps,
InnerBlocks = blockEditor. InnerBlocks;
function treat_style ( val ) {
let tmpstyle = { } ;
if ( val ) {
let vary = val. split ( ';' ) ;
for ( let i = 0 , vcnt = vary. length ; i < vcnt; ++ i ) {
let tmp = [ ] ;
if ( vary[ i ] ) {
tmp[ 0 ] = vary[ i ] . substring ( 0 , vary[ i ] . indexOf ( ':' ) ) ;
tmp[ 1 ] = vary[ i ] . substring ( vary[ i ] . indexOf ( ':' ) + 1 ) ;
tmp[ 2 ] = tmp[ 0 ] . split ( '-' ) ;
if ( tmp[ 2 ] [ 1 ] ) {
let tmpstr = '' ;
for ( let j = 1 , tar_len = tmp[ 2 ] . length ; j < tar_len; ++ j ) {
tmpstr += tmp[ 2 ] [ j ] . slice ( 0 , 1 ) . toUpperCase ( ) + tmp[ 2 ] [ j] . slice ( 1 ) ;
}
tmp[ 2 ] [ 0 ] += tmpstr;
}
if ( tmp[ 1 ] ) {
tmpstyle[ tmp[ 2 ] [ 0 ] ] = tmp[ 1 ] ;
}
}
}
}
return tmpstyle;
}
let dynamicStyles = null ;
function addStyle ( cssstr ) {
if ( ! dynamicStyles ) {
const doc = document ;
if ( null === doc. getElementById ( 'stx-grid-styles' ) ) {
dynamicStyles = doc. createElement ( 'style' ) ;
dynamicStyles. id = 'stx-grid-styles' ;
document . head. appendChild ( dynamicStyles ) ;
}
}
dynamicStyles. sheet. insertRule ( cssstr, dynamicStyles. length ) ;
}
blocks. registerBlockType ( 'stx/grid-wrapper-id' , {
apiVersion : 2 ,
title : 'STX grid-wrapper-id' ,
icon : 'grid-view' ,
category : 'design' ,
description : 'id 及びインラインスタイルを指定でき、css grid で layout できるラッパー。デフォルトで付加されるclass, wp-block-stx-grid-wrapper によってエディタでは css grid layout となる。' ,
attributes : {
idstr : { type : 'string ' , default : '' } ,
styles : { type : 'string' , default : '' } ,
} ,
edit : function ( props ) {
const blockProps = useBlockProps ( { className : props. attributes. className } ) ;
let styles = props. attributes. styles,
idstr = props. attributes. idstr,
elem = {
id : idstr ? idstr : blockProps. id,
} ,
editorgridchildstyle = '#' + ( idstr ? idstr : blockProps. id ) + ' .block-editor-block-list__layout{' + styles + '}' ;
addStyle ( editorgridchildstyle ) ;
let changeId = null ;
function styleChange ( value ) {
clearTimeout ( changeId ) ;
changeId = setTimeout ( ( ) => {
let styleval = 'display:block;' ;
if ( value ) {
styleval = value;
}
if ( ';' === styleval[ ( styleval. length - 1 ) ] ) {
if ( ! idstr ) {
idstr = blockProps. id;
}
const doc = document ;
if ( idstr ) {
if ( null !== doc. getElementById ( idstr ) ) {
const tarel = doc. getElementById ( idstr ) ,
tarchil = tarel. getElementsByClassName ( 'block-editor-block-list__layout' ) ;
if ( tarchil[ 0 ] ) {
tarchil[ 0 ] . style . cssText = styleval;
}
}
}
}
} , 1500 ) ;
}
return (
el (
Fragment,
null ,
el (
InspectorControls,
null ,
el ( 'div' , { id : 'stx_grdiv_sdbr' , style : { fontSize : '1.3em' } } ,
el (
TextControl,
{
label : 'id' ,
help : 'div に設定するid属性' ,
value : idstr,
onChange : function ( newValue ) { props. setAttributes ( { idstr : newValue } ) ; }
}
) ,
el (
TextControl,
{
label : 'styles' ,
help : 'div に設定するインラインスタイル。通常のcssに記述するスタイルで。eq. margin-left:10px;color:red;font-size:1.1em;' ,
value : styles,
onChange : function ( newValue ) { props. setAttributes ( { styles : newValue } ) ; styleChange ( newValue ) ; }
}
) ,
) ,
) ,
el (
'div' ,
Object . assign ( blockProps, elem ) ,
el ( InnerBlocks )
)
)
) ;
} ,
save : function ( props ) {
var blockProps = useBlockProps. save ( ) ;
if ( props. attributes. idstr ) {
blockProps. id = props. attributes. idstr;
}
if ( props. attributes. styles ) {
blockProps. style = treat_style ( props. attributes. styles ) ;
}
return el (
'div' ,
blockProps,
el ( InnerBlocks. Content )
) ;
} ,
} ) ;
} (
window . wp. blocks,
window . wp. element,
window . wp. blockEditor,
window . wp. components,
) ) ;
Copy Expand ‹ › ‹ › ‹ › ‹ › ‹ ›
これで、エディタ画面において css grid レイアウトを表示できるブロック、はできたわけではある。ところで、このブロック、apiVersion: 2 となってはいるけれど、その登録の仕方は現在の block.json を使用する方法ではなく、始めに学んだときのままである。やはり今現在において推奨されている方法というのも知っておかなくては、という思いがある。 で、その場合、non-JSX でもできるのだろうか?ということもあって。
結論から言ってしまえば、もちろんそれも可能だったし、block.json での登録にすれば、そのブロック用のエディタ画面だけでロードさせるスタイルシートの設定などもできるようになる。 そのあたりのことを次ページへと。
page : 1 > 2 3 ☆このページはコンテンツの量が多いので分割しています
Comments feed
Trackback URL : https://strix.main.jp/wp-trackback.php?p=171751