Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
09e8947
Fix variant on dbupdate.twig
brianjhanson Aug 19, 2026
ae78c73
Cleanup "New entry type" button
brianjhanson Aug 19, 2026
4766b9f
Baseline cleanup
brianjhanson Aug 19, 2026
af53957
Own the element selector modal registry
brianjhanson Aug 19, 2026
d947747
Extract shared element index state resolution
brianjhanson Aug 19, 2026
c7e09ed
Merge branch 'feature/ui-adjustments' of github.com:craftcms/cms into…
brianjhanson Aug 19, 2026
d270dc7
Build the element selector modal's chrome with Lit
brianjhanson Aug 19, 2026
4805b7e
Serve index props from the element selector modal body action
brianjhanson Aug 19, 2026
64c7850
Let an element index read its payload from somewhere other than Inertia
brianjhanson Aug 19, 2026
0faabf3
Let an element index navigate without Inertia
brianjhanson Aug 19, 2026
cbfc7c6
Add an element index orchestrator for the selector modal
brianjhanson Aug 19, 2026
84edc6e
Mount the Vue element index inside the selector modal
brianjhanson Aug 19, 2026
dfe651e
Give modal index rows the metadata a relation field needs
brianjhanson Aug 19, 2026
7ceebe4
Load the selector modal's stack only when one opens
brianjhanson Aug 19, 2026
b87c8d7
Merge branch '6.x' of github.com:craftcms/cms into feature/element-se…
brianjhanson Aug 21, 2026
58c00a0
Rebuild craft-dialog on a native <dialog> element
brianjhanson Aug 21, 2026
2340eb6
Add the framework-agnostic element selector core
brianjhanson Aug 21, 2026
2aa5719
Add the element selector modal web component
brianjhanson Aug 21, 2026
1b1616f
Render the element selector modal from Vue on the new core
brianjhanson Aug 21, 2026
f52937d
Fix selection payload collisions and unresolved CpLink in the modal
brianjhanson Aug 22, 2026
effa8cd
Move the element select input onto the new selector modal
brianjhanson Aug 22, 2026
71cb247
Add asset transform support to the selector modal
brianjhanson Aug 22, 2026
06068a5
Document the element selector modal layers
brianjhanson Aug 22, 2026
2f281e3
Retire the Garnish element selector modal
brianjhanson Aug 22, 2026
6e76903
Update the element selector modal README
brianjhanson Aug 22, 2026
4490d83
Cover the folder picker binder and fix its folder id lookup
brianjhanson Aug 22, 2026
f66f3fd
Merge remote-tracking branch 'origin/6.x' into feature/element-select…
brianjhanson Aug 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion cms-assets/resources/icons/custom-icons/c-debug.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion cms-assets/resources/icons/custom-icons/c-outline.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion cms-assets/resources/icons/custom-icons/craft-cms.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion cms-assets/resources/icons/custom-icons/craft-partners.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 1 addition & 2 deletions cms-assets/resources/icons/custom-icons/default-plugin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 0 additions & 6 deletions packages/craftcms-legacy/cp/src/css/_main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2974,12 +2974,6 @@ table:not(.cp-table) {
.chips {
align-items: flex-start;
gap: var(--xs);

&.chips-small {
li {
height: calc(34rem / 16);
}
}
}

.inline-chips {
Expand Down
37 changes: 0 additions & 37 deletions packages/craftcms-legacy/cp/src/js/Craft.js
Original file line number Diff line number Diff line change
Expand Up @@ -1990,7 +1990,6 @@ $.extend(Craft, {
},

_elementIndexClasses: {},
_elementSelectorModalClasses: {},
_elementEditorClasses: {},
_uploaderClasses: {},
_authFormHandlers: {},
Expand Down Expand Up @@ -2031,24 +2030,6 @@ $.extend(Craft, {
this._uploaderClasses[fsType] = func;
},

/**
* Registers an element selector modal class for a given element type.
*
* @param {string} elementType
* @param {function} func
*/
registerElementSelectorModalClass: function (elementType, func) {
if (typeof this._elementSelectorModalClasses[elementType] !== 'undefined') {
throw (
'An element selector modal class has already been registered for the element type “' +
elementType +
'”.'
);
}

this._elementSelectorModalClasses[elementType] = func;
},

registerAuthFormHandler(method, func) {
if (typeof this._authFormHandlers[method] !== 'undefined') {
throw `An authentication form handler has already been registered for the method “${method}”.`;
Expand Down Expand Up @@ -2097,24 +2078,6 @@ $.extend(Craft, {
return uploader;
},

/**
* Creates a new element selector modal for a given element type.
*
* @param {string} elementType
* @param {Object} settings
*/
createElementSelectorModal: function (elementType, settings) {
var func;

if (typeof this._elementSelectorModalClasses[elementType] !== 'undefined') {
func = this._elementSelectorModalClasses[elementType];
} else {
func = Craft.BaseElementSelectorModal;
}

return new func(elementType, settings);
},

/**
* @deprecated in 6.0. Use event listeners directly.
*/
Expand Down
9 changes: 9 additions & 0 deletions packages/craftcms-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@
"development": "./src/components/*.ts",
"default": "./dist/components/*.ts.mjs"
},
"./core": {
"development": "./src/core/element-selector/index.ts",
"types": "./dist/core/element-selector/index.ts.d.mts",
"import": "./dist/core/element-selector/index.ts.mjs"
},
"./core/*": {
"development": "./src/core/*.ts",
"default": "./dist/core/*.ts.mjs"
},
"./services/*": {
"development": "./src/services/*.ts",
"default": "./dist/services/*.ts.mjs"
Expand Down
2 changes: 1 addition & 1 deletion packages/craftcms-ui/scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ async function generateBundle(config = {}) {
)),
...(await resolveFrom('./src/services/**/!(*.(styles|test)).ts')),
...(await resolveFrom('./src/utilities/**/!(*.(styles|test)).ts')),
...(await resolveFrom('./src/services/**/!(*.(styles|test)).ts')),
...(await resolveFrom('./src/factory/**/!(*.(styles|test)).ts')),
...(await resolveFrom('./src/core/**/!(*.(styles|test)).ts')),
},
minify: !isDeveloping,
external: ['lit', '@lion/ui'],
Expand Down
91 changes: 77 additions & 14 deletions packages/craftcms-ui/src/components/dialog/dialog.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,99 @@ import {html} from 'lit';
import './dialog.js';
import type CraftDialog from './dialog.js';

// More on how to set up stories at: https://storybook.js.org/docs/writing-stories
interface DialogArgs {
label: string;
nonModal: boolean;
fullscreen: boolean;
closeOnOutsideClick: boolean;
body: string;
}

const meta = {
title: 'Components/Dialog',
component: 'craft-dialog',
args: {},
args: {
label: 'Dialog',
nonModal: false,
fullscreen: false,
closeOnOutsideClick: false,
body: 'This is some text within a dialog.',
},
parameters: {
layout: 'centered',
},
render: function (args) {
function openDialog() {
const dialog = document.getElementById('storybook-dialog') as CraftDialog;
dialog.opened = true;
render(args: DialogArgs) {
const id = 'storybook-dialog';

function open() {
(document.getElementById(id) as CraftDialog).opened = true;
}

return html`
<craft-dialog label="Dialog" id="storybook-dialog">
This is some text within a dialog.
<craft-dialog
id=${id}
label=${args.label}
?non-modal=${args.nonModal}
?fullscreen=${args.fullscreen}
?close-on-outside-click=${args.closeOnOutsideClick}
>
${args.body}

<craft-button slot="footer" data-dialog="close">Close</craft-button>
</craft-dialog>

<craft-button @click="${openDialog}">Open Dialog</craft-button>
<craft-button @click=${open}>Open Dialog</craft-button>
`;
},
} satisfies Meta<any>;
} satisfies Meta<DialogArgs>;

export default meta;
type Story = StoryObj<any>;
type Story = StoryObj<DialogArgs>;

export const Default: Story = {};

/** No footer slotted — the footer row collapses rather than leaving a gap. */
export const NoFooter: Story = {
render(args: DialogArgs) {
function open() {
(document.getElementById('storybook-dialog-bare') as CraftDialog).opened =
true;
}

return html`
<craft-dialog id="storybook-dialog-bare" label=${args.label}>
${args.body}
</craft-dialog>

<craft-button @click=${open}>Open Dialog</craft-button>
`;
},
};

/**
* Opened with `show()` rather than `showModal()`, so the dialog stays out of the
* top layer and content that appends itself to `<body>` — most legacy CP menus —
* still paints above it. The backdrop, Escape and focus containment are the
* component's own here.
*/
export const NonModal: Story = {
args: {nonModal: true},
};

export const Fullscreen: Story = {
args: {fullscreen: true},
};

/** Long content scrolls inside the body rather than growing the surface. */
export const Scrolling: Story = {
args: {
body: Array.from(
{length: 40},
(_, i) => `Line ${i + 1} of a dialog body that has to scroll. `
).join(''),
},
};

// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
export const Default: Story = {
args: {},
export const ClosesOnOutsideClick: Story = {
args: {closeOnOutsideClick: true},
};
125 changes: 125 additions & 0 deletions packages/craftcms-ui/src/components/dialog/dialog.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import {css} from 'lit';

export default css`
:host {
display: contents;

/*
Sizing hooks. Declared on \`:host\` so an outer-tree rule or an inline
style on the host still wins — shadow-tree \`:host\` rules always lose to
the outer tree — and so a subclass can go near-fullscreen without
reaching into this component's internals.
*/
--_dialog-inline-size: var(--c-dialog-inline-size, auto);
--_dialog-min-inline-size: var(
--c-dialog-min-inline-size,
min(90vw, 24rem)
);
--_dialog-max-inline-size: var(
--c-dialog-max-inline-size,
min(90vw, 40rem)
);
--_dialog-max-block-size: var(--c-dialog-max-block-size, 85dvh);
}

:host([fullscreen]) {
--_dialog-inline-size: var(--c-dialog-inline-size, 100vw);
--_dialog-min-inline-size: var(--c-dialog-min-inline-size, 100vw);
--_dialog-max-inline-size: var(--c-dialog-max-inline-size, 100vw);
--_dialog-max-block-size: var(--c-dialog-max-block-size, 100dvh);
}

dialog {
padding: 0;
border: 0;
background: none;
color: inherit;
max-width: none;
max-height: none;
overflow: visible;
}

dialog::backdrop {
background-color: rgb(0 0 0 / 0.25);
}

/*
Non-modal dialogs get no \`::backdrop\` — that pseudo only paints for the
top layer — so one is rendered instead. \`show()\` also leaves the dialog in
normal flow, hence the fixed positioning to centre it.
*/
.backdrop {
position: fixed;
inset: 0;
background-color: rgb(0 0 0 / 0.25);
}

:host([non-modal]) dialog {
position: fixed;
inset: 0;
margin: auto;
z-index: 100;
}

.surface {
display: grid;
/* header / body / footer — the body is the only row that flexes. */
grid-template-rows: auto 1fr auto;
inline-size: var(--_dialog-inline-size);
min-inline-size: var(--_dialog-min-inline-size);
max-inline-size: var(--_dialog-max-inline-size);
max-block-size: var(--_dialog-max-block-size);
background-color: var(--c-surface-raised);
border-radius: var(--c-radius-md);
box-shadow: var(--c-shadow-lg);
overflow: hidden;
}

:host([fullscreen]) .surface {
border-radius: 0;
}

.header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: var(--c-spacing-md);
padding-inline: var(--c-spacing-lg);
padding-block-start: var(--c-spacing-lg);
padding-block-end: var(--c-spacing-md);
}

.title {
font-size: 1.25em;
margin: 0;
}

.close {
background: none;
border: none;
cursor: pointer;
color: inherit;
padding: var(--c-spacing-xs);
line-height: 1;
}

.body {
/*
Pairs with \`1fr\` above: without an explicit \`min-block-size: 0\` a grid
item floors at its content height, so a long slotted index would grow the
surface past \`--_dialog-max-block-size\` instead of scrolling inside it.
*/
min-block-size: 0;
overflow: auto;
padding-inline: var(--c-spacing-lg);
padding-block-end: var(--c-spacing-lg);
}

.footer {
display: flex;
justify-content: flex-end;
gap: var(--c-spacing-sm);
padding-inline: var(--c-spacing-lg);
padding-block-end: var(--c-spacing-lg);
}
`;
Loading
Loading