Improve Global Searching in admin panel#2327
Conversation
📝 WalkthroughWalkthroughThe PR integrates a third-party global search modal plugin by adding the Composer dependency, registering it in the admin panel provider, bundling compiled Tailwind CSS styling with theme variables and utilities, and implementing JavaScript modules for localStorage-backed search history/favorites management and DOM event-driven modal interaction. ChangesGlobal Search Modal Feature
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
public/js/charrafimed/global-search-modal/components/global-search-modal-observer.js (3)
25-28: 💤 Low valueConsider removing redundant keypress handler.
The
keypressevent listener is redundant sincekeydown(registered at line 18) already covers all keyboard input including character keys. Thekeypressevent is also a legacy event that's been deprecated in favor ofkeydownandbeforeinput.♻️ Proposed fix
inputElement.setAttribute("readonly", true); inputElement.setAttribute("tabindex", "-1"); } }, - inputElement.addEventListener("keypress", (event) => { - event.preventDefault(); - event.stopPropagation(); - }, true); - inputElement.setAttribute("readonly", true);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@public/js/charrafimed/global-search-modal/components/global-search-modal-observer.js` around lines 25 - 28, Remove the redundant "keypress" listener on inputElement: locate the inputElement.addEventListener("keypress", ...) block and delete it, leaving the existing "keydown" listener (registered earlier) to handle keyboard input; ensure no other code depends on the keypress handler before removal and keep event.preventDefault()/stopPropagation() behavior in the "keydown" handler if needed.
57-57: 💤 Low valuePass string value to setAttribute.
setAttributeexpects string values. While the number0will be coerced to the string"0", it's better to be explicit and pass the string directly for consistency.♻️ Proposed fix
inputElement.disabled = false; inputElement.readOnly = false; - inputElement.setAttribute("tabindex", 0); + inputElement.setAttribute("tabindex", "0"); } });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@public/js/charrafimed/global-search-modal/components/global-search-modal-observer.js` at line 57, The call inputElement.setAttribute("tabindex", 0) passes a number; change it to pass a string by using "0" so setAttribute receives a string value (update the setAttribute invocation on inputElement to use "0" instead of 0).
4-4: 💤 Low valueRemove unused property.
The
observerproperty is declared but never used in this module. Consider removing it to keep the code clean.♻️ Proposed fix
function observer() { return { - observer: null, modalOpen: false, init: function() {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@public/js/charrafimed/global-search-modal/components/global-search-modal-observer.js` at line 4, The exported object in global-search-modal-observer.js declares an unused property named "observer"; remove the "observer" property declaration from the object (and any related/commented code in that module) so the module no longer contains an unused symbol, and run a quick grep for "observer" in that file to confirm there are no remaining references before committing.public/css/charrafimed/global-search-modal/global-search-modal.css (1)
1-1215: ⚡ Quick winConsider excluding compiled CSS from linting.
This file is compiled Tailwind CSS output (as indicated by the header comment). Stylelint violations in generated/compiled files are expected and should not be manually fixed, as changes would be overwritten on rebuild.
Consider adding this file to your
.stylelintignoreor similar linting configuration to suppress false positives.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@public/css/charrafimed/global-search-modal/global-search-modal.css` around lines 1 - 1215, This is generated Tailwind output (see header "/*! tailwindcss v4.1.12" and large compiled rules like :root, :host), so instead of editing it, add public/css/charrafimed/global-search-modal/global-search-modal.css to the stylelint ignore list (or update your lint config to exclude compiled CSS directories) or add an appropriate generated-file ignore rule; alternatively, if you prefer a per-file suppression, prepend a stylelint disable directive to the generated file as part of your build step so lint rules no longer run on this compiled output.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@public/js/charrafimed/global-search-modal/components/global-search-modal-observer.js`:
- Line 29: The code incorrectly uses inputElement.setAttribute("readonly", true)
and later sets readonly to "false" in listenForModalClose; change these to use
the DOM property or proper boolean attribute handling: replace
setAttribute("readonly", true) with inputElement.readOnly = true, and replace
the code that sets readonly to false (in listenForModalClose) with
inputElement.readOnly = false (or use removeAttribute("readonly") if you prefer
attribute manipulation) so the readonly state is toggled correctly without
creating readonly="false".
In
`@public/js/charrafimed/global-search-modal/components/global-search-modal-search.js`:
- Around line 23-24: The getLocalStorage method currently calls
localStorage.getItem and JSON.parse directly and can throw in private mode,
quota/security errors, or on invalid JSON; wrap the localStorage.getItem +
JSON.parse sequence in a try-catch inside getLocalStorage, catch any exception,
optionally log the error, and return an empty array as the safe fallback so
callers of getLocalStorage (refer to getLocalStorage) never receive a thrown
exception or undefined.
---
Nitpick comments:
In `@public/css/charrafimed/global-search-modal/global-search-modal.css`:
- Around line 1-1215: This is generated Tailwind output (see header "/*!
tailwindcss v4.1.12" and large compiled rules like :root, :host), so instead of
editing it, add
public/css/charrafimed/global-search-modal/global-search-modal.css to the
stylelint ignore list (or update your lint config to exclude compiled CSS
directories) or add an appropriate generated-file ignore rule; alternatively, if
you prefer a per-file suppression, prepend a stylelint disable directive to the
generated file as part of your build step so lint rules no longer run on this
compiled output.
In
`@public/js/charrafimed/global-search-modal/components/global-search-modal-observer.js`:
- Around line 25-28: Remove the redundant "keypress" listener on inputElement:
locate the inputElement.addEventListener("keypress", ...) block and delete it,
leaving the existing "keydown" listener (registered earlier) to handle keyboard
input; ensure no other code depends on the keypress handler before removal and
keep event.preventDefault()/stopPropagation() behavior in the "keydown" handler
if needed.
- Line 57: The call inputElement.setAttribute("tabindex", 0) passes a number;
change it to pass a string by using "0" so setAttribute receives a string value
(update the setAttribute invocation on inputElement to use "0" instead of 0).
- Line 4: The exported object in global-search-modal-observer.js declares an
unused property named "observer"; remove the "observer" property declaration
from the object (and any related/commented code in that module) so the module no
longer contains an unused symbol, and run a quick grep for "observer" in that
file to confirm there are no remaining references before committing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: bac01114-6adb-405b-8d21-2e9b36136975
⛔ Files ignored due to path filters (1)
composer.lockis excluded by!**/*.lock
📒 Files selected for processing (5)
app/Providers/Filament/AdminPanelProvider.phpcomposer.jsonpublic/css/charrafimed/global-search-modal/global-search-modal.csspublic/js/charrafimed/global-search-modal/components/global-search-modal-observer.jspublic/js/charrafimed/global-search-modal/components/global-search-modal-search.js
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@public/js/filament/forms/components/rich-editor.js`:
- Line 123: This change was made in a generated Filament bundle
(public/js/filament/forms/components/rich-editor.js) and must not be edited
directly; revert this edit in the generated file and instead make the fix in the
upstream source (the rich editor extension that defines the customBlock node -
look for the mf/$.create call and related methods like addNodeView,
addAttributes, addProseMirrorPlugins), then run the repository's asset
build/publish step to regenerate public/js/filament assets so the corrected code
(e.g., changes to customBlock node behavior, attributes, or button handlers) is
produced into the bundle.
In `@public/js/filament/schemas/components/tabs.js`:
- Line 1: The reset-schema-component-state event handler (boundResetHandler)
reads i.detail.livewireId and i.detail.schemaKey directly which can throw if
detail is missing; update the handler to first null-safe guard the detail (e.g.,
const detail = i.detail ?? {} or use optional chaining) and then compare
detail.livewireId and detail.schemaKey, keeping the existing conditions (also
preserve checks for T and u) and the this.$nextTick behavior; because this file
is a generated asset under public/js/filament, make the change in the Filament
source/override where boundResetHandler is defined and then regenerate the
published assets so the compiled tabs.js contains the null-safe guard.
In `@public/js/filament/schemas/components/wizard.js`:
- Line 1: The reset handler currently dereferences t.detail.livewireId and
t.detail.schemaKey in the boundResetHandler inside the l(...) component, which
can throw if event.detail is missing; update the boundResetHandler to first
check that t.detail is non-null/defined (e.g., if (!t.detail) return or guard
the comparisons), then compare livewireId/schemaKey, and only call
this.$nextTick to reset the step when appropriate; apply this change in the
upstream source for the Filament wizard component (the function l / its
boundResetHandler) so regenerated assets under public/js/filament/ will include
the fix.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 0954b4a3-d6ef-4f32-b7dd-4d27ba23abb2
⛔ Files ignored due to path filters (1)
composer.lockis excluded by!**/*.lock
📒 Files selected for processing (7)
composer.jsonpublic/css/filament/filament/app.csspublic/js/filament/forms/components/rich-editor.jspublic/js/filament/schemas/components/tabs.jspublic/js/filament/schemas/components/wizard.jspublic/js/filament/schemas/schemas.jspublic/js/filament/widgets/components/chart.js
|
|
||
| `);return!i||!s?!1:t.chain().command(({tr:l})=>(l.delete(r.pos-2,r.pos),!0)).exitCode().run()},ArrowDown:({editor:t})=>{if(!this.options.exitOnArrowDown)return!1;let{state:e}=t,{selection:n,doc:r}=e,{$from:o,empty:i}=n;if(!i||o.parent.type!==this.type||!(o.parentOffset===o.parent.nodeSize-2))return!1;let l=o.after();return l===void 0?!1:r.nodeAt(l)?t.commands.command(({tr:c})=>(c.setSelection(L.near(r.resolve(l))),!0)):t.commands.exitCode()}}},addInputRules(){return[zn({find:v0,type:this.type,getAttributes:t=>({language:t[1]})}),zn({find:M0,type:this.type,getAttributes:t=>({language:t[1]})})]},addProseMirrorPlugins(){return[new P({key:new H("codeBlockVSCodeHandler"),props:{handlePaste:(t,e)=>{if(!e.clipboardData||this.editor.isActive(this.type.name))return!1;let n=e.clipboardData.getData("text/plain"),r=e.clipboardData.getData("vscode-editor-data"),o=r?JSON.parse(r):void 0,i=o?.mode;if(!n||!i)return!1;let{tr:s,schema:l}=t.state,a=l.text(n.replace(/\r\n?/g,` | ||
| `));return s.replaceSelectionWith(this.type.create({language:i},a)),s.selection.$from.parent.type!==this.type&&s.setSelection(D.near(s.doc.resolve(Math.max(0,s.selection.from-2)))),s.setMeta("paste",!0),t.dispatch(s),!0}}})]}}),pf=T0;var mf=$.create({name:"customBlock",group:"block",atom:!0,defining:!0,draggable:!0,selectable:!0,isolating:!0,allowGapCursor:!0,inline:!1,addNodeView(){return({editor:t,node:e,getPos:n,HTMLAttributes:r,decorations:o,extension:i})=>{let s=document.createElement("div");s.setAttribute("data-config",e.attrs.config),s.setAttribute("data-id",e.attrs.id),s.setAttribute("data-type","customBlock");let l=document.createElement("div");if(l.className="fi-fo-rich-editor-custom-block-header fi-not-prose",s.appendChild(l),t.isEditable&&typeof e.attrs.config=="object"&&e.attrs.config!==null&&Object.keys(e.attrs.config).length>0){let c=document.createElement("div");c.className="fi-fo-rich-editor-custom-block-edit-btn-ctn",l.appendChild(c);let d=document.createElement("button");d.className="fi-icon-btn",d.type="button",d.innerHTML=i.options.editCustomBlockButtonIconHtml,d.addEventListener("click",()=>i.options.editCustomBlockUsing(e.attrs.id,e.attrs.config)),c.appendChild(d)}let a=document.createElement("p");if(a.className="fi-fo-rich-editor-custom-block-heading",a.textContent=e.attrs.label,l.appendChild(a),t.isEditable){let c=document.createElement("div");c.className="fi-fo-rich-editor-custom-block-delete-btn-ctn",l.appendChild(c);let d=document.createElement("button");d.className="fi-icon-btn",d.type="button",d.innerHTML=i.options.deleteCustomBlockButtonIconHtml,d.addEventListener("click",()=>t.chain().setNodeSelection(n()).deleteSelection().run()),c.appendChild(d)}if(e.attrs.preview){let c=document.createElement("div"),d=["fi-fo-rich-editor-custom-block-preview"];e.attrs.shouldApplyProseStylingToPreview||d.push("fi-not-prose"),c.className=d.join(" "),c.innerHTML=new TextDecoder().decode(Uint8Array.from(atob(e.attrs.preview),u=>u.charCodeAt(0))),s.appendChild(c)}return{dom:s}}},addOptions(){return{deleteCustomBlockButtonIconHtml:null,editCustomBlockButtonIconHtml:null,editCustomBlockUsing:()=>{},insertCustomBlockUsing:()=>{}}},addAttributes(){return{config:{default:null,parseHTML:t=>JSON.parse(t.getAttribute("data-config"))},id:{default:null,parseHTML:t=>t.getAttribute("data-id"),renderHTML:t=>t.id?{"data-id":t.id}:{}},label:{default:null,parseHTML:t=>t.getAttribute("data-label"),rendered:!1},preview:{default:null,parseHTML:t=>t.getAttribute("data-preview"),rendered:!1},shouldApplyProseStylingToPreview:{default:!1,rendered:!1}}},parseHTML(){return[{tag:`div[data-type="${this.name}"]`}]},renderHTML({HTMLAttributes:t}){return["div",O(t)]},addKeyboardShortcuts(){return{Backspace:()=>this.editor.commands.command(({tr:t,state:e})=>{let n=!1,{selection:r}=e,{empty:o,anchor:i}=r;if(!o)return!1;let s=new te,l=0;return e.doc.nodesBetween(i-1,i,(a,c)=>{if(a.type.name===this.name)return n=!0,s=a,l=c,!1}),n})}},addProseMirrorPlugins(){let{insertCustomBlockUsing:t}=this.options;return[new P({props:{handleDrop(e,n){if(!n||(n.preventDefault(),!n.dataTransfer.getData("customBlock")))return!1;let r=n.dataTransfer.getData("customBlock");return t(r,e.posAtCoords({left:n.clientX,top:n.clientY}).pos),!1}}})]}});var Qo=(t,e)=>e.view.domAtPos(t).node.offsetParent!==null,A0=(t,e,n)=>{for(let r=t.depth;r>0;r-=1){let o=t.node(r),i=e(o),s=Qo(t.start(r),n);if(i&&s)return{pos:r>0?t.before(r):0,start:t.start(r),depth:r,node:o}}},gf=(t,e)=>{let{state:n,view:r,extensionManager:o}=t,{schema:i,selection:s}=n,{empty:l,$anchor:a}=s,c=!!o.extensions.find(y=>y.name==="gapCursor");if(!l||a.parent.type!==i.nodes.detailsSummary||!c||e==="right"&&a.parentOffset!==a.parent.nodeSize-2)return!1;let d=qe(y=>y.type===i.nodes.details)(s);if(!d)return!1;let u=on(d.node,y=>y.type===i.nodes.detailsContent);if(!u.length||Qo(d.start+u[0].pos+1,t))return!1;let h=n.doc.resolve(d.pos+d.node.nodeSize),p=ce.findFrom(h,1,!1);if(!p)return!1;let{tr:m}=n,g=new ce(p);return m.setSelection(g),m.scrollIntoView(),r.dispatch(m),!0},yf=$.create({name:"details",content:"detailsSummary detailsContent",group:"block",defining:!0,isolating:!0,allowGapCursor:!1,addOptions(){return{persist:!1,openClassName:"is-open",HTMLAttributes:{}}},addAttributes(){return this.options.persist?{open:{default:!1,parseHTML:t=>t.hasAttribute("open"),renderHTML:({open:t})=>t?{open:""}:{}}}:[]},parseHTML(){return[{tag:"details"}]},renderHTML({HTMLAttributes:t}){return["details",O(this.options.HTMLAttributes,t),0]},...Ht({nodeName:"details",content:"block"}),addNodeView(){return({editor:t,getPos:e,node:n,HTMLAttributes:r})=>{let o=document.createElement("div"),i=O(this.options.HTMLAttributes,r,{"data-type":this.name});Object.entries(i).forEach(([c,d])=>o.setAttribute(c,d));let s=document.createElement("button");s.type="button",o.append(s);let l=document.createElement("div");o.append(l);let a=c=>{if(c!==void 0)if(c){if(o.classList.contains(this.options.openClassName))return;o.classList.add(this.options.openClassName)}else{if(!o.classList.contains(this.options.openClassName))return;o.classList.remove(this.options.openClassName)}else o.classList.toggle(this.options.openClassName);let d=new Event("toggleDetailsContent"),u=l.querySelector(':scope > div[data-type="detailsContent"]');u?.dispatchEvent(d)};return n.attrs.open&&setTimeout(()=>a()),s.addEventListener("click",()=>{if(a(),!this.options.persist){t.commands.focus(void 0,{scrollIntoView:!1});return}if(t.isEditable&&typeof e=="function"){let{from:c,to:d}=t.state.selection;t.chain().command(({tr:u})=>{let f=e();if(!f)return!1;let h=u.doc.nodeAt(f);return h?.type!==this.type?!1:(u.setNodeMarkup(f,void 0,{open:!h.attrs.open}),!0)}).setTextSelection({from:c,to:d}).focus(void 0,{scrollIntoView:!1}).run()}}),{dom:o,contentDOM:l,ignoreMutation(c){return c.type==="selection"?!1:!o.contains(c.target)||o===c.target},update:c=>c.type!==this.type?!1:(c.attrs.open!==void 0&&a(c.attrs.open),!0)}}},addCommands(){return{setDetails:()=>({state:t,chain:e})=>{var n;let{schema:r,selection:o}=t,{$from:i,$to:s}=o,l=i.blockRange(s);if(!l)return!1;let a=t.doc.slice(l.start,l.end);if(!r.nodes.detailsContent.contentMatch.matchFragment(a.content))return!1;let d=((n=a.toJSON())==null?void 0:n.content)||[];return e().insertContentAt({from:l.start,to:l.end},{type:this.name,content:[{type:"detailsSummary"},{type:"detailsContent",content:d}]}).setTextSelection(l.start+2).run()},unsetDetails:()=>({state:t,chain:e})=>{let{selection:n,schema:r}=t,o=qe(y=>y.type===this.type)(n);if(!o)return!1;let i=on(o.node,y=>y.type===r.nodes.detailsSummary),s=on(o.node,y=>y.type===r.nodes.detailsContent);if(!i.length||!s.length)return!1;let l=i[0],a=s[0],c=o.pos,d=t.doc.resolve(c),u=c+o.node.nodeSize,f={from:c,to:u},h=a.node.content.toJSON()||[],p=d.parent.type.contentMatch.defaultType,g=[p?.create(null,l.node.content).toJSON(),...h];return e().insertContentAt(f,g).setTextSelection(c+1).run()}}},addKeyboardShortcuts(){return{Backspace:()=>{let{schema:t,selection:e}=this.editor.state,{empty:n,$anchor:r}=e;return!n||r.parent.type!==t.nodes.detailsSummary?!1:r.parentOffset!==0?this.editor.commands.command(({tr:o})=>{let i=r.pos-1,s=r.pos;return o.delete(i,s),!0}):this.editor.commands.unsetDetails()},Enter:({editor:t})=>{let{state:e,view:n}=t,{schema:r,selection:o}=e,{$head:i}=o;if(i.parent.type!==r.nodes.detailsSummary)return!1;let s=Qo(i.after()+1,t),l=s?e.doc.nodeAt(i.after()):i.node(-2);if(!l)return!1;let a=s?0:i.indexAfter(-1),c=Pn(l.contentMatchAt(a));if(!c||!l.canReplaceWith(a,a,c))return!1;let d=c.createAndFill();if(!d)return!1;let u=s?i.after()+1:i.after(-1),f=e.tr.replaceWith(u,u,d),h=f.doc.resolve(u),p=L.near(h,1);return f.setSelection(p),f.scrollIntoView(),n.dispatch(f),!0},ArrowRight:({editor:t})=>gf(t,"right"),ArrowDown:({editor:t})=>gf(t,"down")}},addProseMirrorPlugins(){return[new P({key:new H("detailsSelection"),appendTransaction:(t,e,n)=>{let{editor:r,type:o}=this;if(r.view.composing||!t.some(y=>y.selectionSet)||!e.selection.empty||!n.selection.empty||!Fo(n,o.name))return;let{$from:a}=n.selection;if(Qo(a.pos,r))return;let d=A0(a,y=>y.type===o,r);if(!d)return;let u=on(d.node,y=>y.type===n.schema.nodes.detailsSummary);if(!u.length)return;let f=u[0],p=(e.selection.from<n.selection.from?"forward":"backward")==="forward"?d.start+f.pos:d.pos+f.pos+f.node.nodeSize,m=D.create(n.doc,p);return n.tr.setSelection(m)}})]}}),bf=$.create({name:"detailsContent",content:"block+",defining:!0,selectable:!1,addOptions(){return{HTMLAttributes:{}}},parseHTML(){return[{tag:`div[data-type="${this.name}"]`}]},renderHTML({HTMLAttributes:t}){return["div",O(this.options.HTMLAttributes,t,{"data-type":this.name}),0]},addNodeView(){return({HTMLAttributes:t})=>{let e=document.createElement("div"),n=O(this.options.HTMLAttributes,t,{"data-type":this.name,hidden:"hidden"});return Object.entries(n).forEach(([r,o])=>e.setAttribute(r,o)),e.addEventListener("toggleDetailsContent",()=>{e.toggleAttribute("hidden")}),{dom:e,contentDOM:e,ignoreMutation(r){return r.type==="selection"?!1:!e.contains(r.target)||e===r.target},update:r=>r.type===this.type}}},addKeyboardShortcuts(){return{Enter:({editor:t})=>{let{state:e,view:n}=t,{selection:r}=e,{$from:o,empty:i}=r,s=qe(z=>z.type===this.type)(r);if(!i||!s||!s.node.childCount)return!1;let l=o.index(s.depth),{childCount:a}=s.node;if(!(a===l+1))return!1;let d=s.node.type.contentMatch.defaultType,u=d?.createAndFill();if(!u)return!1;let f=e.doc.resolve(s.pos+1),h=a-1,p=s.node.child(h),m=f.posAtIndex(h,s.depth);if(!p.eq(u))return!1;let y=o.node(-3);if(!y)return!1;let b=o.indexAfter(-3),w=Pn(y.contentMatchAt(b));if(!w||!y.canReplaceWith(b,b,w))return!1;let C=w.createAndFill();if(!C)return!1;let{tr:x}=e,S=o.after(-2);x.replaceWith(S,S,C);let k=x.doc.resolve(S),E=L.near(k,1);x.setSelection(E);let M=m,A=m+p.nodeSize;return x.delete(M,A),x.scrollIntoView(),n.dispatch(x),!0}}},...Ht({nodeName:"detailsContent"})}),wf=$.create({name:"detailsSummary",content:"text*",defining:!0,selectable:!1,isolating:!0,addOptions(){return{HTMLAttributes:{}}},parseHTML(){return[{tag:"summary"}]},renderHTML({HTMLAttributes:t}){return["summary",O(this.options.HTMLAttributes,t),0]},...Ht({nodeName:"detailsSummary",content:"inline"})});var E0=$.create({name:"doc",topNode:!0,content:"block+",renderMarkdown:(t,e)=>t.content?e.renderChildren(t.content,` | ||
| `));return s.replaceSelectionWith(this.type.create({language:i},a)),s.selection.$from.parent.type!==this.type&&s.setSelection(D.near(s.doc.resolve(Math.max(0,s.selection.from-2)))),s.setMeta("paste",!0),t.dispatch(s),!0}}})]}}),pf=T0;var mf=$.create({name:"customBlock",group:"block",atom:!0,defining:!0,draggable:!0,selectable:!0,isolating:!0,allowGapCursor:!0,inline:!1,addNodeView(){return({editor:t,node:e,getPos:n,HTMLAttributes:r,decorations:o,extension:i})=>{let s=document.createElement("div");s.setAttribute("data-config",JSON.stringify(e.attrs.config)),s.setAttribute("data-id",e.attrs.id),s.setAttribute("data-type","customBlock");let l=document.createElement("div");if(l.className="fi-fo-rich-editor-custom-block-header fi-not-prose",s.appendChild(l),t.isEditable&&typeof e.attrs.config=="object"&&e.attrs.config!==null&&Object.keys(e.attrs.config).length>0){let c=document.createElement("div");c.className="fi-fo-rich-editor-custom-block-edit-btn-ctn",l.appendChild(c);let d=document.createElement("button");d.className="fi-icon-btn",d.type="button",d.innerHTML=i.options.editCustomBlockButtonIconHtml,d.addEventListener("click",()=>i.options.editCustomBlockUsing(e.attrs.id,e.attrs.config)),c.appendChild(d)}let a=document.createElement("p");if(a.className="fi-fo-rich-editor-custom-block-heading",a.textContent=e.attrs.label,l.appendChild(a),t.isEditable){let c=document.createElement("div");c.className="fi-fo-rich-editor-custom-block-delete-btn-ctn",l.appendChild(c);let d=document.createElement("button");d.className="fi-icon-btn",d.type="button",d.innerHTML=i.options.deleteCustomBlockButtonIconHtml,d.addEventListener("click",()=>t.chain().setNodeSelection(n()).deleteSelection().run()),c.appendChild(d)}if(e.attrs.preview){let c=document.createElement("div"),d=["fi-fo-rich-editor-custom-block-preview"];e.attrs.shouldApplyProseStylingToPreview||d.push("fi-not-prose"),c.className=d.join(" "),c.innerHTML=new TextDecoder().decode(Uint8Array.from(atob(e.attrs.preview),u=>u.charCodeAt(0))),s.appendChild(c)}return{dom:s}}},addOptions(){return{deleteCustomBlockButtonIconHtml:null,editCustomBlockButtonIconHtml:null,editCustomBlockUsing:()=>{},insertCustomBlockUsing:()=>{}}},addAttributes(){return{config:{default:null,parseHTML:t=>JSON.parse(t.getAttribute("data-config")),renderHTML:t=>t.config?{"data-config":JSON.stringify(t.config)}:{}},id:{default:null,parseHTML:t=>t.getAttribute("data-id"),renderHTML:t=>t.id?{"data-id":t.id}:{}},label:{default:null,parseHTML:t=>t.getAttribute("data-label"),rendered:!1},preview:{default:null,parseHTML:t=>t.getAttribute("data-preview"),rendered:!1},shouldApplyProseStylingToPreview:{default:!1,rendered:!1}}},parseHTML(){return[{tag:`div[data-type="${this.name}"]`}]},renderHTML({HTMLAttributes:t}){return["div",O({"data-type":"customBlock"},t)]},addKeyboardShortcuts(){return{Backspace:()=>this.editor.commands.command(({tr:t,state:e})=>{let n=!1,{selection:r}=e,{empty:o,anchor:i}=r;if(!o)return!1;let s=new te,l=0;return e.doc.nodesBetween(i-1,i,(a,c)=>{if(a.type.name===this.name)return n=!0,s=a,l=c,!1}),n})}},addProseMirrorPlugins(){let{insertCustomBlockUsing:t}=this.options;return[new P({props:{handleDrop(e,n){if(!n||(n.preventDefault(),!n.dataTransfer.getData("customBlock")))return!1;let r=n.dataTransfer.getData("customBlock");return t(r,e.posAtCoords({left:n.clientX,top:n.clientY}).pos),!1}}})]}});var Qo=(t,e)=>e.view.domAtPos(t).node.offsetParent!==null,A0=(t,e,n)=>{for(let r=t.depth;r>0;r-=1){let o=t.node(r),i=e(o),s=Qo(t.start(r),n);if(i&&s)return{pos:r>0?t.before(r):0,start:t.start(r),depth:r,node:o}}},gf=(t,e)=>{let{state:n,view:r,extensionManager:o}=t,{schema:i,selection:s}=n,{empty:l,$anchor:a}=s,c=!!o.extensions.find(y=>y.name==="gapCursor");if(!l||a.parent.type!==i.nodes.detailsSummary||!c||e==="right"&&a.parentOffset!==a.parent.nodeSize-2)return!1;let d=qe(y=>y.type===i.nodes.details)(s);if(!d)return!1;let u=on(d.node,y=>y.type===i.nodes.detailsContent);if(!u.length||Qo(d.start+u[0].pos+1,t))return!1;let h=n.doc.resolve(d.pos+d.node.nodeSize),p=ce.findFrom(h,1,!1);if(!p)return!1;let{tr:m}=n,g=new ce(p);return m.setSelection(g),m.scrollIntoView(),r.dispatch(m),!0},yf=$.create({name:"details",content:"detailsSummary detailsContent",group:"block",defining:!0,isolating:!0,allowGapCursor:!1,addOptions(){return{persist:!1,openClassName:"is-open",HTMLAttributes:{}}},addAttributes(){return this.options.persist?{open:{default:!1,parseHTML:t=>t.hasAttribute("open"),renderHTML:({open:t})=>t?{open:""}:{}}}:[]},parseHTML(){return[{tag:"details"}]},renderHTML({HTMLAttributes:t}){return["details",O(this.options.HTMLAttributes,t),0]},...Ht({nodeName:"details",content:"block"}),addNodeView(){return({editor:t,getPos:e,node:n,HTMLAttributes:r})=>{let o=document.createElement("div"),i=O(this.options.HTMLAttributes,r,{"data-type":this.name});Object.entries(i).forEach(([c,d])=>o.setAttribute(c,d));let s=document.createElement("button");s.type="button",o.append(s);let l=document.createElement("div");o.append(l);let a=c=>{if(c!==void 0)if(c){if(o.classList.contains(this.options.openClassName))return;o.classList.add(this.options.openClassName)}else{if(!o.classList.contains(this.options.openClassName))return;o.classList.remove(this.options.openClassName)}else o.classList.toggle(this.options.openClassName);let d=new Event("toggleDetailsContent"),u=l.querySelector(':scope > div[data-type="detailsContent"]');u?.dispatchEvent(d)};return n.attrs.open&&setTimeout(()=>a()),s.addEventListener("click",()=>{if(a(),!this.options.persist){t.commands.focus(void 0,{scrollIntoView:!1});return}if(t.isEditable&&typeof e=="function"){let{from:c,to:d}=t.state.selection;t.chain().command(({tr:u})=>{let f=e();if(!f)return!1;let h=u.doc.nodeAt(f);return h?.type!==this.type?!1:(u.setNodeMarkup(f,void 0,{open:!h.attrs.open}),!0)}).setTextSelection({from:c,to:d}).focus(void 0,{scrollIntoView:!1}).run()}}),{dom:o,contentDOM:l,ignoreMutation(c){return c.type==="selection"?!1:!o.contains(c.target)||o===c.target},update:c=>c.type!==this.type?!1:(c.attrs.open!==void 0&&a(c.attrs.open),!0)}}},addCommands(){return{setDetails:()=>({state:t,chain:e})=>{var n;let{schema:r,selection:o}=t,{$from:i,$to:s}=o,l=i.blockRange(s);if(!l)return!1;let a=t.doc.slice(l.start,l.end);if(!r.nodes.detailsContent.contentMatch.matchFragment(a.content))return!1;let d=((n=a.toJSON())==null?void 0:n.content)||[];return e().insertContentAt({from:l.start,to:l.end},{type:this.name,content:[{type:"detailsSummary"},{type:"detailsContent",content:d}]}).setTextSelection(l.start+2).run()},unsetDetails:()=>({state:t,chain:e})=>{let{selection:n,schema:r}=t,o=qe(y=>y.type===this.type)(n);if(!o)return!1;let i=on(o.node,y=>y.type===r.nodes.detailsSummary),s=on(o.node,y=>y.type===r.nodes.detailsContent);if(!i.length||!s.length)return!1;let l=i[0],a=s[0],c=o.pos,d=t.doc.resolve(c),u=c+o.node.nodeSize,f={from:c,to:u},h=a.node.content.toJSON()||[],p=d.parent.type.contentMatch.defaultType,g=[p?.create(null,l.node.content).toJSON(),...h];return e().insertContentAt(f,g).setTextSelection(c+1).run()}}},addKeyboardShortcuts(){return{Backspace:()=>{let{schema:t,selection:e}=this.editor.state,{empty:n,$anchor:r}=e;return!n||r.parent.type!==t.nodes.detailsSummary?!1:r.parentOffset!==0?this.editor.commands.command(({tr:o})=>{let i=r.pos-1,s=r.pos;return o.delete(i,s),!0}):this.editor.commands.unsetDetails()},Enter:({editor:t})=>{let{state:e,view:n}=t,{schema:r,selection:o}=e,{$head:i}=o;if(i.parent.type!==r.nodes.detailsSummary)return!1;let s=Qo(i.after()+1,t),l=s?e.doc.nodeAt(i.after()):i.node(-2);if(!l)return!1;let a=s?0:i.indexAfter(-1),c=Pn(l.contentMatchAt(a));if(!c||!l.canReplaceWith(a,a,c))return!1;let d=c.createAndFill();if(!d)return!1;let u=s?i.after()+1:i.after(-1),f=e.tr.replaceWith(u,u,d),h=f.doc.resolve(u),p=L.near(h,1);return f.setSelection(p),f.scrollIntoView(),n.dispatch(f),!0},ArrowRight:({editor:t})=>gf(t,"right"),ArrowDown:({editor:t})=>gf(t,"down")}},addProseMirrorPlugins(){return[new P({key:new H("detailsSelection"),appendTransaction:(t,e,n)=>{let{editor:r,type:o}=this;if(r.view.composing||!t.some(y=>y.selectionSet)||!e.selection.empty||!n.selection.empty||!Fo(n,o.name))return;let{$from:a}=n.selection;if(Qo(a.pos,r))return;let d=A0(a,y=>y.type===o,r);if(!d)return;let u=on(d.node,y=>y.type===n.schema.nodes.detailsSummary);if(!u.length)return;let f=u[0],p=(e.selection.from<n.selection.from?"forward":"backward")==="forward"?d.start+f.pos:d.pos+f.pos+f.node.nodeSize,m=D.create(n.doc,p);return n.tr.setSelection(m)}})]}}),bf=$.create({name:"detailsContent",content:"block+",defining:!0,selectable:!1,addOptions(){return{HTMLAttributes:{}}},parseHTML(){return[{tag:`div[data-type="${this.name}"]`}]},renderHTML({HTMLAttributes:t}){return["div",O(this.options.HTMLAttributes,t,{"data-type":this.name}),0]},addNodeView(){return({HTMLAttributes:t})=>{let e=document.createElement("div"),n=O(this.options.HTMLAttributes,t,{"data-type":this.name,hidden:"hidden"});return Object.entries(n).forEach(([r,o])=>e.setAttribute(r,o)),e.addEventListener("toggleDetailsContent",()=>{e.toggleAttribute("hidden")}),{dom:e,contentDOM:e,ignoreMutation(r){return r.type==="selection"?!1:!e.contains(r.target)||e===r.target},update:r=>r.type===this.type}}},addKeyboardShortcuts(){return{Enter:({editor:t})=>{let{state:e,view:n}=t,{selection:r}=e,{$from:o,empty:i}=r,s=qe(z=>z.type===this.type)(r);if(!i||!s||!s.node.childCount)return!1;let l=o.index(s.depth),{childCount:a}=s.node;if(!(a===l+1))return!1;let d=s.node.type.contentMatch.defaultType,u=d?.createAndFill();if(!u)return!1;let f=e.doc.resolve(s.pos+1),h=a-1,p=s.node.child(h),m=f.posAtIndex(h,s.depth);if(!p.eq(u))return!1;let y=o.node(-3);if(!y)return!1;let b=o.indexAfter(-3),w=Pn(y.contentMatchAt(b));if(!w||!y.canReplaceWith(b,b,w))return!1;let C=w.createAndFill();if(!C)return!1;let{tr:x}=e,S=o.after(-2);x.replaceWith(S,S,C);let k=x.doc.resolve(S),E=L.near(k,1);x.setSelection(E);let M=m,A=m+p.nodeSize;return x.delete(M,A),x.scrollIntoView(),n.dispatch(x),!0}}},...Ht({nodeName:"detailsContent"})}),wf=$.create({name:"detailsSummary",content:"text*",defining:!0,selectable:!1,isolating:!0,addOptions(){return{HTMLAttributes:{}}},parseHTML(){return[{tag:"summary"}]},renderHTML({HTMLAttributes:t}){return["summary",O(this.options.HTMLAttributes,t),0]},...Ht({nodeName:"detailsSummary",content:"inline"})});var E0=$.create({name:"doc",topNode:!0,content:"block+",renderMarkdown:(t,e)=>t.content?e.renderChildren(t.content,` |
There was a problem hiding this comment.
Avoid direct edits in generated Filament asset bundles.
This file is in public/js/filament/ and appears to be generated/published output. Please move this fix to the source/upstream file and regenerate assets, otherwise this change is fragile and likely to be lost on the next publish.
Based on learnings: files under public/js/filament/ are auto-generated Filament assets and should be changed upstream or via repo configuration, then re-published.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@public/js/filament/forms/components/rich-editor.js` at line 123, This change
was made in a generated Filament bundle
(public/js/filament/forms/components/rich-editor.js) and must not be edited
directly; revert this edit in the generated file and instead make the fix in the
upstream source (the rich editor extension that defines the customBlock node -
look for the mf/$.create call and related methods like addNodeView,
addAttributes, addProseMirrorPlugins), then run the repository's asset
build/publish step to regenerate public/js/filament assets so the corrected code
(e.g., changes to customBlock node behavior, attributes, or button handlers) is
produced into the bundle.
| @@ -1 +1 @@ | |||
| function v({activeTab:w,isScrollable:f,isTabPersistedInQueryString:m,livewireId:g,tab:T,tabQueryStringKey:r}){return{boundResizeHandler:null,isScrollable:f,resizeDebounceTimer:null,tab:T,unsubscribeLivewireHook:null,withinDropdownIndex:null,withinDropdownMounted:!1,init(){let t=this.getTabs(),e=new URLSearchParams(window.location.search);m&&e.has(r)&&t.includes(e.get(r))&&(this.tab=e.get(r)),(!this.tab||!t.includes(this.tab))&&(this.tab=t[w-1]),this.$watch("tab",()=>{this.updateQueryString(),this.autofocusFields()}),this.autofocusFields(!0),this.unsubscribeLivewireHook=Livewire.interceptMessage(({message:i,onSuccess:a})=>{a(()=>{this.$nextTick(()=>{if(i.component.id!==g)return;let l=this.getTabs();l.includes(this.tab)||(this.tab=l[w-1]??this.tab)})})}),f||(this.boundResizeHandler=this.debouncedUpdateTabsWithinDropdown.bind(this),window.addEventListener("resize",this.boundResizeHandler),this.updateTabsWithinDropdown())},calculateAvailableWidth(t){let e=window.getComputedStyle(t);return Math.floor(t.clientWidth)-Math.ceil(parseFloat(e.paddingLeft))*2},calculateContainerGap(t){let e=window.getComputedStyle(t);return Math.ceil(parseFloat(e.columnGap))},calculateDropdownIconWidth(t){let e=t.querySelector(".fi-icon");return Math.ceil(e.clientWidth)},calculateTabItemGap(t){let e=window.getComputedStyle(t);return Math.ceil(parseFloat(e.columnGap)||8)},calculateTabItemPadding(t){let e=window.getComputedStyle(t);return Math.ceil(parseFloat(e.paddingLeft))+Math.ceil(parseFloat(e.paddingRight))},findOverflowIndex(t,e,i,a,l,h){let u=t.map(n=>Math.ceil(n.clientWidth)),b=t.map(n=>{let c=n.querySelector(".fi-tabs-item-label"),s=n.querySelector(".fi-badge"),o=Math.ceil(c.clientWidth),d=s?Math.ceil(s.clientWidth):0;return{label:o,badge:d,total:o+(d>0?a+d:0)}});for(let n=0;n<t.length;n++){let c=u.slice(0,n+1).reduce((p,y)=>p+y,0),s=n*i,o=b.slice(n+1),d=o.length>0,D=d?Math.max(...o.map(p=>p.total)):0,W=d?l+D+a+h+i:0;if(c+s+W>e)return n}return-1},get isDropdownButtonVisible(){return this.withinDropdownMounted?this.withinDropdownIndex===null?!1:this.getTabs().findIndex(e=>e===this.tab)<this.withinDropdownIndex:!0},getTabs(){return this.$refs.tabsData?JSON.parse(this.$refs.tabsData.value):[]},updateQueryString(){if(!m)return;let t=new URL(window.location.href);t.searchParams.set(r,this.tab),history.replaceState(null,document.title,t.toString())},autofocusFields(t=!1){this.$nextTick(()=>{if(t&&document.activeElement&&document.activeElement!==document.body&&this.$el.compareDocumentPosition(document.activeElement)&Node.DOCUMENT_POSITION_PRECEDING)return;let e=this.$el.querySelectorAll(".fi-sc-tabs-tab.fi-active [autofocus]");for(let i of e)if(i.focus(),document.activeElement===i)break})},debouncedUpdateTabsWithinDropdown(){clearTimeout(this.resizeDebounceTimer),this.resizeDebounceTimer=setTimeout(()=>this.updateTabsWithinDropdown(),150)},async updateTabsWithinDropdown(){this.withinDropdownIndex=null,this.withinDropdownMounted=!1,await this.$nextTick();let t=this.$el.querySelector(".fi-tabs"),e=t.querySelector(".fi-tabs-item:last-child"),i=Array.from(t.children).slice(0,-1),a=i.map(s=>s.style.display);i.forEach(s=>s.style.display=""),t.offsetHeight;let l=this.calculateAvailableWidth(t),h=this.calculateContainerGap(t),u=this.calculateDropdownIconWidth(e),b=this.calculateTabItemGap(i[0]),n=this.calculateTabItemPadding(i[0]),c=this.findOverflowIndex(i,l,h,b,n,u);i.forEach((s,o)=>s.style.display=a[o]),c!==-1&&(this.withinDropdownIndex=c),this.withinDropdownMounted=!0},destroy(){this.unsubscribeLivewireHook?.(),this.boundResizeHandler&&window.removeEventListener("resize",this.boundResizeHandler),clearTimeout(this.resizeDebounceTimer)}}}export{v as default}; | |||
| function x({activeTab:h,isScrollable:m,isTabPersisted:T,isTabPersistedInQueryString:u,livewireId:g,schemaKey:D,tab:W,tabQueryStringKey:r}){return{boundResizeHandler:null,boundResetHandler:null,isScrollable:m,resizeDebounceTimer:null,tab:W,unsubscribeLivewireHook:null,withinDropdownIndex:null,withinDropdownMounted:!1,init(){let t=this.getTabs(),e=new URLSearchParams(window.location.search);u&&e.has(r)&&t.includes(e.get(r))&&(this.tab=e.get(r)),(!this.tab||!t.includes(this.tab))&&(this.tab=t[h-1]),this.$watch("tab",()=>{this.updateQueryString(),this.autofocusFields()}),this.autofocusFields(!0),this.unsubscribeLivewireHook=Livewire.interceptMessage(({message:i,onSuccess:a})=>{a(()=>{this.$nextTick(()=>{if(i.component.id!==g)return;let l=this.getTabs();l.includes(this.tab)||(this.tab=l[h-1]??this.tab)})})}),this.boundResetHandler=i=>{i.detail.livewireId!==g||i.detail.schemaKey!==D||T||u||this.$nextTick(()=>{this.tab=this.getTabs()[h-1]??this.tab})},window.addEventListener("reset-schema-component-state",this.boundResetHandler),m||(this.boundResizeHandler=this.debouncedUpdateTabsWithinDropdown.bind(this),window.addEventListener("resize",this.boundResizeHandler),this.updateTabsWithinDropdown())},calculateAvailableWidth(t){let e=window.getComputedStyle(t);return Math.floor(t.clientWidth)-Math.ceil(parseFloat(e.paddingLeft))*2},calculateContainerGap(t){let e=window.getComputedStyle(t);return Math.ceil(parseFloat(e.columnGap))},calculateDropdownIconWidth(t){let e=t.querySelector(".fi-icon");return Math.ceil(e.clientWidth)},calculateTabItemGap(t){let e=window.getComputedStyle(t);return Math.ceil(parseFloat(e.columnGap)||8)},calculateTabItemPadding(t){let e=window.getComputedStyle(t);return Math.ceil(parseFloat(e.paddingLeft))+Math.ceil(parseFloat(e.paddingRight))},findOverflowIndex(t,e,i,a,l,b){let p=t.map(n=>Math.ceil(n.clientWidth)),w=t.map(n=>{let d=n.querySelector(".fi-tabs-item-label"),s=n.querySelector(".fi-badge"),o=Math.ceil(d.clientWidth),c=s?Math.ceil(s.clientWidth):0;return{label:o,badge:c,total:o+(c>0?a+c:0)}});for(let n=0;n<t.length;n++){let d=p.slice(0,n+1).reduce((f,I)=>f+I,0),s=n*i,o=w.slice(n+1),c=o.length>0,v=c?Math.max(...o.map(f=>f.total)):0,y=c?l+v+a+b+i:0;if(d+s+y>e)return n}return-1},get isDropdownButtonVisible(){return this.withinDropdownMounted?this.withinDropdownIndex===null?!1:this.getTabs().findIndex(e=>e===this.tab)<this.withinDropdownIndex:!0},getTabs(){return this.$refs.tabsData?JSON.parse(this.$refs.tabsData.value):[]},updateQueryString(){if(!u)return;let t=new URL(window.location.href);t.searchParams.set(r,this.tab),history.replaceState(null,document.title,t.toString())},autofocusFields(t=!1){this.$nextTick(()=>{if(t&&document.activeElement&&document.activeElement!==document.body&&this.$el.compareDocumentPosition(document.activeElement)&Node.DOCUMENT_POSITION_PRECEDING)return;let e=this.$el.querySelectorAll(".fi-sc-tabs-tab.fi-active [autofocus]");for(let i of e)if(i.focus(),document.activeElement===i)break})},debouncedUpdateTabsWithinDropdown(){clearTimeout(this.resizeDebounceTimer),this.resizeDebounceTimer=setTimeout(()=>this.updateTabsWithinDropdown(),150)},async updateTabsWithinDropdown(){this.withinDropdownIndex=null,this.withinDropdownMounted=!1,await this.$nextTick();let t=this.$el.querySelector(".fi-tabs"),e=t.querySelector(".fi-tabs-item:last-child"),i=Array.from(t.children).slice(0,-1),a=i.map(s=>s.style.display);i.forEach(s=>s.style.display=""),t.offsetHeight;let l=this.calculateAvailableWidth(t),b=this.calculateContainerGap(t),p=this.calculateDropdownIconWidth(e),w=this.calculateTabItemGap(i[0]),n=this.calculateTabItemPadding(i[0]),d=this.findOverflowIndex(i,l,b,w,n,p);i.forEach((s,o)=>s.style.display=a[o]),d!==-1&&(this.withinDropdownIndex=d),this.withinDropdownMounted=!0},destroy(){this.unsubscribeLivewireHook?.(),this.boundResetHandler&&window.removeEventListener("reset-schema-component-state",this.boundResetHandler),this.boundResizeHandler&&window.removeEventListener("resize",this.boundResizeHandler),clearTimeout(this.resizeDebounceTimer)}}}export{x as default}; | |||
There was a problem hiding this comment.
Guard reset-schema-component-state detail access before reading nested fields.
Line 1 reads i.detail.livewireId / i.detail.schemaKey directly. If the event is fired without a detail object, this throws and breaks tab logic. Add a null-safe guard (const detail = i.detail ?? {} or optional chaining) before comparisons.
Based on learnings: files under public/js/filament/ are generated assets, so apply this guard in the Filament source/override and regenerate published assets.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@public/js/filament/schemas/components/tabs.js` at line 1, The
reset-schema-component-state event handler (boundResetHandler) reads
i.detail.livewireId and i.detail.schemaKey directly which can throw if detail is
missing; update the handler to first null-safe guard the detail (e.g., const
detail = i.detail ?? {} or use optional chaining) and then compare
detail.livewireId and detail.schemaKey, keeping the existing conditions (also
preserve checks for T and u) and the this.$nextTick behavior; because this file
is a generated asset under public/js/filament, make the change in the Filament
source/override where boundResetHandler is defined and then regenerate the
published assets so the compiled tabs.js contains the null-safe guard.
| @@ -1 +1 @@ | |||
| function p({isSkippable:i,isStepPersistedInQueryString:n,key:r,startStep:o,stepQueryStringKey:h}){return{step:null,init(){this.step=this.getSteps().at(o-1),this.$watch("step",()=>{this.updateQueryString(),this.autofocusFields()}),this.autofocusFields(!0)},async requestNextStep(){await this.$wire.callSchemaComponentMethod(r,"nextStep",{currentStepIndex:this.getStepIndex(this.step)})},goToNextStep(){let t=this.getStepIndex(this.step)+1;t>=this.getSteps().length||(this.step=this.getSteps()[t],this.scroll())},goToPreviousStep(){let t=this.getStepIndex(this.step)-1;t<0||(this.step=this.getSteps()[t],this.scroll())},goToStep(t){let e=this.getStepIndex(t);e<=-1||!i&&e>this.getStepIndex(this.step)||(this.step=t,this.scroll())},scroll(){this.$nextTick(()=>{this.$refs.header?.children[this.getStepIndex(this.step)].scrollIntoView({behavior:"smooth",block:"start"})})},autofocusFields(t=!1){this.$nextTick(()=>{if(t&&document.activeElement&&document.activeElement!==document.body&&this.$el.compareDocumentPosition(document.activeElement)&Node.DOCUMENT_POSITION_PRECEDING)return;let e=this.$refs[`step-${this.step}`]?.querySelectorAll("[autofocus]")??[];for(let s of e)if(s.focus(),document.activeElement===s)break})},getStepIndex(t){let e=this.getSteps().findIndex(s=>s===t);return e===-1?0:e},getSteps(){return JSON.parse(this.$refs.stepsData.value)},isFirstStep(){return this.getStepIndex(this.step)<=0},isLastStep(){return this.getStepIndex(this.step)+1>=this.getSteps().length},isStepAccessible(t){return i||this.getStepIndex(this.step)>this.getStepIndex(t)},updateQueryString(){if(!n)return;let t=new URL(window.location.href);t.searchParams.set(h,this.step),history.replaceState(null,document.title,t.toString())}}}export{p as default}; | |||
| function l({isSkippable:i,isStepPersistedInQueryString:n,key:o,livewireId:h,schemaKey:p,startStep:r,stepQueryStringKey:d}){return{boundResetHandler:null,step:null,init(){this.step=this.getSteps().at(r-1),this.$watch("step",()=>{this.updateQueryString(),this.autofocusFields()}),this.autofocusFields(!0),this.boundResetHandler=t=>{t.detail.livewireId!==h||t.detail.schemaKey!==p||n||this.$nextTick(()=>{this.step=this.getSteps().at(r-1)??this.step})},window.addEventListener("reset-schema-component-state",this.boundResetHandler)},async requestNextStep(){await this.$wire.callSchemaComponentMethod(o,"nextStep",{currentStepIndex:this.getStepIndex(this.step)})},goToNextStep(){let t=this.getStepIndex(this.step)+1;t>=this.getSteps().length||(this.step=this.getSteps()[t],this.scroll())},goToPreviousStep(){let t=this.getStepIndex(this.step)-1;t<0||(this.step=this.getSteps()[t],this.scroll())},goToStep(t){let e=this.getStepIndex(t);e<=-1||!i&&e>this.getStepIndex(this.step)||(this.step=t,this.scroll())},scroll(){this.$nextTick(()=>{this.$refs.header?.children[this.getStepIndex(this.step)].scrollIntoView({behavior:"smooth",block:"start"})})},autofocusFields(t=!1){this.$nextTick(()=>{if(t&&document.activeElement&&document.activeElement!==document.body&&this.$el.compareDocumentPosition(document.activeElement)&Node.DOCUMENT_POSITION_PRECEDING)return;let e=this.$refs[`step-${this.step}`]?.querySelectorAll("[autofocus]")??[];for(let s of e)if(s.focus(),document.activeElement===s)break})},getStepIndex(t){let e=this.getSteps().findIndex(s=>s===t);return e===-1?0:e},getSteps(){return JSON.parse(this.$refs.stepsData.value)},isFirstStep(){return this.getStepIndex(this.step)<=0},isLastStep(){return this.getStepIndex(this.step)+1>=this.getSteps().length},isStepAccessible(t){return i||this.getStepIndex(this.step)>this.getStepIndex(t)},updateQueryString(){if(!n)return;let t=new URL(window.location.href);t.searchParams.set(d,this.step),history.replaceState(null,document.title,t.toString())},destroy(){this.boundResetHandler&&window.removeEventListener("reset-schema-component-state",this.boundResetHandler)}}}export{l as default}; | |||
There was a problem hiding this comment.
Make reset handler resilient to missing event.detail.
Line 1 dereferences t.detail.livewireId / t.detail.schemaKey without checking t.detail. Add a null-safe guard before those reads to avoid runtime errors during reset events.
Based on learnings: files under public/js/filament/ are generated assets, so implement this in the upstream/source layer and republish assets.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@public/js/filament/schemas/components/wizard.js` at line 1, The reset handler
currently dereferences t.detail.livewireId and t.detail.schemaKey in the
boundResetHandler inside the l(...) component, which can throw if event.detail
is missing; update the boundResetHandler to first check that t.detail is
non-null/defined (e.g., if (!t.detail) return or guard the comparisons), then
compare livewireId/schemaKey, and only call this.$nextTick to reset the step
when appropriate; apply this change in the upstream source for the Filament
wizard component (the function l / its boundResetHandler) so regenerated assets
under public/js/filament/ will include the fix.
Added filament global search plugin to improve on filaments stock global search.