Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
cf183a1
wip
duncanmcclean Dec 15, 2025
d0cc323
convert stack to composition api
duncanmcclean Dec 15, 2025
0958c66
wip
duncanmcclean Dec 15, 2025
2b660db
refactor open states
duncanmcclean Dec 15, 2025
1066aac
add beforeClose prop for modals
duncanmcclean Dec 15, 2025
b816f60
Move the stack's close callback logic into the stack component
duncanmcclean Dec 15, 2025
1ffe942
wip
duncanmcclean Dec 15, 2025
71c4853
only emit an event if the state actually changes
duncanmcclean Dec 15, 2025
24e8c5b
replace `close` slot prop with StackClose component
duncanmcclean Dec 15, 2025
cf2b0d2
add `opened` event to modals & stacks to allow parent components to f…
duncanmcclean Dec 15, 2025
7fe29f5
wip
duncanmcclean Dec 15, 2025
dbfc4fc
update stack usage
duncanmcclean Dec 15, 2025
e61903e
merge `narrow`/`half`/`full` props into new `size` prop
duncanmcclean Dec 15, 2025
4064c36
wip
duncanmcclean Dec 15, 2025
b1a2e9f
stacks shouldn't be full by default
duncanmcclean Dec 15, 2025
e60e828
Wire up stack title prop
duncanmcclean Dec 15, 2025
12dcd82
don't think we're using this anywhere. remove.
duncanmcclean Dec 15, 2025
4ebf86d
add data attribute
duncanmcclean Dec 15, 2025
e433e20
add stacks page to storybook docs
duncanmcclean Dec 15, 2025
1e7f6cf
add stack example to the playground
duncanmcclean Dec 15, 2025
fc39433
ensure portal & esc binding are properly destroyed when stack is closed
duncanmcclean Dec 15, 2025
70a94d8
wip
duncanmcclean Dec 15, 2025
fb45533
storybook docs
duncanmcclean Dec 16, 2025
5b06bb9
Merge branch 'master' into unify-modals-and-stacks
duncanmcclean Dec 17, 2025
46e4408
Merge branch 'master' into unify-modals-and-stacks
duncanmcclean Dec 19, 2025
25caba0
attempt to avoid merge conflicts when storybook pr is merged in
duncanmcclean Dec 19, 2025
c1fbba5
Merge branch 'master' into unify-modals-and-stacks
duncanmcclean Dec 19, 2025
5e9e4a6
Merge branch 'master' into unify-modals-and-stacks
duncanmcclean Jan 5, 2026
701de19
Merge branch 'master' into unify-modals-and-stacks
jasonvarga Jan 5, 2026
62a329a
no tabs. 👋💥
jasonvarga Jan 5, 2026
9f79281
only clean up after the stack has animated out. when cleaning up befo…
jasonvarga Jan 5, 2026
6433771
extract cleanup method
jasonvarga Jan 5, 2026
70c24cf
use immediate on watcher that already has the logic
jasonvarga Jan 5, 2026
073b302
fix focus scope. allow header close button to be included in scope.
jasonvarga Jan 5, 2026
4f5b090
use a primitive as child for the trigger so a div doesnt get rendered
jasonvarga Jan 6, 2026
4dcecc8
hasComponent composable can accept props
jasonvarga Jan 7, 2026
866d5c1
bring back closed event
jasonvarga Jan 7, 2026
935e317
rework stack components
jasonvarga Jan 7, 2026
960569e
adjust usages
jasonvarga Jan 7, 2026
4021c04
update storybook ...
jasonvarga Jan 7, 2026
894e4bf
typescript, why not.
jasonvarga Jan 7, 2026
49bd3aa
header actions
jasonvarga Jan 7, 2026
9151e51
position floating x the same as the header
jasonvarga Jan 7, 2026
6def460
footer slots
jasonvarga Jan 7, 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
10 changes: 10 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { StorybookConfig } from '@storybook/vue3-vite';
import { resolve } from 'path';

const config: StorybookConfig = {
stories: [
Expand All @@ -16,6 +17,15 @@ const config: StorybookConfig = {
docgen: 'vue-component-meta'
}
},
async viteFinal(config) {
if (config.resolve) {
config.resolve.alias = {
...config.resolve.alias,
'@api': resolve(process.cwd(), 'resources/js/api.js'),
};
}
return config;
},
};

export default config;
13 changes: 7 additions & 6 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,14 @@ import PortalVue from 'portal-vue';
import FullscreenHeader from '@/components/publish/FullscreenHeader.vue';
import Portal from '@/components/portals/Portal.vue';
import PortalTargets from '@/components/portals/PortalTargets.vue';
import { portals, stacks } from '@api';

// Intercept Inertia navigation and log to Actions tab.
router.on('before', (event) => {
action('inertia navigate')(event.detail.visit.url);
return false;
});

// const portals = markRaw(new Portals());
// const stacks = new Stacks(portals);

setup(async (app) => {
window.__ = translate;

Expand Down Expand Up @@ -53,8 +51,8 @@ setup(async (app) => {
app.config.globalProperties.__ = translate;
app.config.globalProperties.$date = new DateFormatter;
app.config.globalProperties.cp_url = (url) => url;
// app.config.globalProperties.$portals = portals;
// app.config.globalProperties.$stacks = stacks;
app.config.globalProperties.$portals = portals;
app.config.globalProperties.$stacks = stacks;

app.use(PortalVue, { portalName: 'v-portal' });

Expand Down Expand Up @@ -129,7 +127,10 @@ const preview: Preview = {
}
}

return story();
return {
components: { PortalTargets },
template: '<div><story /><PortalTargets /></div>',
};
},
],
};
Expand Down
9 changes: 9 additions & 0 deletions .storybook/storybook.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
@import '../resources/css/ui.css';
@import '../resources/css/core/utilities.css';
@import '../resources/css/elements/tables.css';
@import '../resources/css/components/stacks.css';
@custom-variant dark (&:where(.dark, .dark *));

.sbdocs h1:not(.sbdocs-preview *, .sbdocs-preview h1),
Expand Down Expand Up @@ -46,3 +47,11 @@
.dark .sbdocs-preview {
background: var(--theme-color-content-bg);
}

.docs-story div[scale="1"] {
transform: none !important;
}

.stacks-on-stacks {
z-index: 100;
}
4 changes: 4 additions & 0 deletions packages/cms/src/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ export const {
Switch,
TabContent,
Stack,
StackClose,
StackHeader,
StackFooter,
StackContent,
Table,
TableCell,
TableColumn,
Expand Down
4 changes: 4 additions & 0 deletions resources/js/bootstrap/cms/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ export {
Switch,
TabContent,
Stack,
StackClose,
StackHeader,
StackFooter,
StackContent,
Table,
TableCell,
TableColumn,
Expand Down
3 changes: 3 additions & 0 deletions resources/js/components/Config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { ref } from 'vue';
import { data_get } from '@/bootstrap/globals';

export default class Config {
config = ref({});

initialize(initialConfig) {
this.config = ref(initialConfig);
}
Expand Down
10 changes: 6 additions & 4 deletions resources/js/components/assets/Editor/Editor.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<ui-stack name="asset-editor" :before-close="shouldClose" :full="true" @closed="$emit('closed')" v-slot="{ close }">
<Stack size="full" open inset ref="stack" :before-close="shouldClose" @update:open="$emit('closed')" :show-close-button="false">
<div
class="asset-editor relative flex h-full flex-col rounded-sm bg-gray-100 dark:bg-dark-800"
:class="isImage ? 'is-image' : 'is-file'"
Expand All @@ -22,7 +22,7 @@
{{ asset.path }}
</span>
</button>
<ui-button variant="ghost" icon="x" class="absolute top-1.5 end-1.5" round @click="confirmClose(close)" :aria-label="__('Close Editor')" />
<ui-button variant="ghost" icon="x" class="absolute top-1.5 end-1.5" round @click="confirmClose()" :aria-label="__('Close Editor')" />
</header>

<div class="flex flex-1 grow flex-col overflow-auto md:flex-row md:justify-between">
Expand Down Expand Up @@ -174,7 +174,7 @@
@cancel="closingWithChanges = false"
/>
</div>
</ui-stack>
</Stack>
</template>

<script>
Expand All @@ -188,6 +188,7 @@ import {
PublishContainer,
PublishTabs,
Icon,
Stack,
} from '@ui';
import ItemActions from '@/components/actions/ItemActions.vue';

Expand All @@ -204,6 +205,7 @@ export default {
PublishContainer,
PublishTabs,
Icon,
Stack,
},

props: {
Expand Down Expand Up @@ -435,7 +437,7 @@ export default {
},

confirmClose(close) {
if (this.shouldClose()) close();
if (this.shouldClose()) this.$refs.stack.close();
},

confirmCloseWithChanges() {
Expand Down
22 changes: 13 additions & 9 deletions resources/js/components/blueprints/Fields.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,22 @@
<ui-button icon="add-circle" :text="__('Create Field')" @click="createField" />
</div>

<ui-stack
name="fieldtype-selector"
v-if="isSelectingNewFieldtype"
<Stack
v-model:open="isSelectingNewFieldtype"
@closed="isSelectingNewFieldtype = false"
:title="__('Fieldtypes')"
icon="cog"
v-slot="{ close }"
>
<fieldtype-selector @closed="close" @selected="fieldtypeSelected" />
</ui-stack>
</Stack>

<ui-stack
name="field-settings"
v-if="pendingCreatedField != null"
<Stack
:open="pendingCreatedField != null"
@update:open="(value) => { if (!value) pendingCreatedField = null }"
@closed="pendingCreatedField = null"
v-slot="{ close }"
inset
>
<field-settings
ref="settings"
Expand All @@ -59,7 +61,7 @@
@committed="fieldCreated"
@closed="close"
/>
</ui-stack>
</Stack>
</div>
</template>

Expand All @@ -71,6 +73,7 @@ import LinkFields from './LinkFields.vue';
import FieldtypeSelector from '../fields/FieldtypeSelector.vue';
import FieldSettings from '../fields/Settings.vue';
import CanDefineLocalizable from '../fields/CanDefineLocalizable';
import { Stack } from '@/components/ui';

export default {
mixins: [CanDefineLocalizable],
Expand All @@ -81,6 +84,7 @@ export default {
LinkFields,
FieldtypeSelector,
FieldSettings,
Stack,
},

props: {
Expand Down Expand Up @@ -129,7 +133,7 @@ export default {
},
};

this.$nextTick(() => (this.pendingCreatedField = pending));
setTimeout(() => (this.pendingCreatedField = pending), 500); // wait for stack to close
},

createField() {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/blueprints/ImportField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</div>
<div class="flex items-center gap-2">
<ui-button size="sm" icon="trash" variant="subtle" @click.prevent="$emit('deleted')" v-tooltip="__('Remove')" />
<ui-stack name="field-settings" v-if="isEditing" @closed="editorClosed">
<ui-stack :open="isEditing" @update:open="editorClosed" inset :show-close-button="false">
<field-settings
ref="settings"
:id="field._id"
Expand Down
28 changes: 15 additions & 13 deletions resources/js/components/blueprints/LinkFields.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
<template>
<div>
<ui-button icon="link" @click="open = true" :text="__('Link Existing')" />

<ui-stack narrow v-if="open" @closed="open = false" name="field-linker" v-slot="{ close }">
<div class="h-full overflow-auto bg-white dark:bg-gray-800 p-3 rounded-l-xl">
<header class="flex items-center justify-between pl-3">
<Heading :text="__('Link Fields')" size="lg" icon="fieldsets" />
<Button type="button" icon="x" variant="subtle" @click="close" />
</header>

<div class="flex-1 overflow-auto px-3 py-4">
<Stack
size="narrow"
v-model:open="open"
:title="__('Link Fields')"
icon="fieldsets"
>
<template #trigger>
<Button icon="link" :text="__('Link Existing')" />
</template>

<div class="">
<div class="">
<Field
:label="__('Link a single field')"
:instructions="__('Changes to this field in the fieldset will stay in sync.')"
Expand Down Expand Up @@ -90,17 +92,17 @@
/>
</div>
</div>
</ui-stack>
</Stack>
</div>
</template>

<script>
import uniqid from 'uniqid';
import { Combobox, Button, Input, Heading, Field } from '@/components/ui';
import { Combobox, Button, Input, Heading, Field, Stack, StackClose } from '@/components/ui';
import { usePage } from '@inertiajs/vue3';

export default {
components: { Heading, Combobox, Button, Input, Field },
components: { Heading, Combobox, Button, Input, Field, Stack, StackClose },

props: {
excludeFieldset: String,
Expand Down
7 changes: 4 additions & 3 deletions resources/js/components/blueprints/RegularField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<ui-button inset size="sm" icon="trash" variant="subtle" @click.prevent="$emit('deleted')" v-tooltip="__('Remove')" />
</div>

<ui-stack name="field-settings" v-if="isEditing" @closed="editorClosed">
<Stack :open="isEditing" @update:open="editorClosed" inset :show-close-button="false">
<field-settings
ref="settings"
:id="field._id"
Expand All @@ -45,7 +45,7 @@
@committed="settingsUpdated"
@closed="editorClosed"
/>
</ui-stack>
</Stack>
</div>
</div>
</div>
Expand All @@ -59,7 +59,7 @@ import WidthSelector from '../fields/WidthSelector.vue';
import CanDefineLocalizable from '../fields/CanDefineLocalizable';
import titleize from '../../util/titleize';
import deslugify from '../../util/deslugify';
import { Icon } from '@/components/ui';
import { Icon, Stack } from '@/components/ui';

export default {
mixins: [Field, CanDefineLocalizable],
Expand All @@ -68,6 +68,7 @@ export default {
FieldSettings,
WidthSelector,
Icon,
Stack,
},

props: ['suggestableConditionFields'],
Expand Down
19 changes: 6 additions & 13 deletions resources/js/components/blueprints/Section.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,13 @@
</ui-panel>

<ui-stack
narrow
v-if="editingSection"
@opened="() => $nextTick(() => $refs.displayInput.focus())"
size="narrow"
:open="editingSection !== false"
:title="editText"
@closed="editCancelled"
@opened="() => $nextTick(() => $refs.displayInput.focus())"
>
<div class="h-full overflow-scroll overflow-x-auto bg-white px-6 dark:bg-dark-800">
<header class="py-2 -mx-6 px-6 border-b border-gray-200 dark:border-gray-700 mb-5">
<div class="flex items-center justify-between">
<ui-heading size="lg">
{{ editText }}
</ui-heading>
<ui-button icon="x" variant="ghost" class="-me-2" @click="editCancelled" />
</div>
</header>
<div class="">
<div class="space-y-6">
<ui-field :label="__('Display')">
<ui-input ref="displayInput" type="text" v-model="editingSection.display" />
Expand Down Expand Up @@ -182,7 +175,7 @@ export default {

isSoloNarrowStack() {
const stacks = this.$stacks.stacks();
return stacks.length === 1 && stacks[0]?.data?.vm?.narrow === true;
return stacks.length === 1 && stacks[0]?.data?.vm?.size === 'narrow';
},
},

Expand Down
Loading
Loading