Major overhaul to the theme and now functioning.

This commit is contained in:
2026-01-05 16:07:30 -05:00
parent 5823ca3c39
commit a475dfeab6
5218 changed files with 1643729 additions and 13229 deletions
@@ -0,0 +1,99 @@
.v-dialog {
align-items: center;
justify-content: center;
margin: auto;
}
.v-dialog > .v-overlay__content {
max-height: calc(100% - 48px);
width: calc(100% - 48px);
max-width: calc(100% - 48px);
margin: 24px;
}
.v-dialog > .v-overlay__content,
.v-dialog > .v-overlay__content > form {
display: flex;
flex-direction: column;
min-height: 0;
}
.v-dialog > .v-overlay__content > .v-card,
.v-dialog > .v-overlay__content > .v-sheet,
.v-dialog > .v-overlay__content > form > .v-card,
.v-dialog > .v-overlay__content > form > .v-sheet {
--v-scrollbar-offset: 0px;
border-radius: 4px;
overflow-y: auto;
flex: 1 1 100%;
}
.v-dialog > .v-overlay__content > .v-card,
.v-dialog > .v-overlay__content > .v-sheet,
.v-dialog > .v-overlay__content > form > .v-card,
.v-dialog > .v-overlay__content > form > .v-sheet {
box-shadow: 0px 11px 15px -7px var(--v-shadow-key-umbra-opacity, rgba(0, 0, 0, 0.2)), 0px 24px 38px 3px var(--v-shadow-key-penumbra-opacity, rgba(0, 0, 0, 0.14)), 0px 9px 46px 8px var(--v-shadow-key-ambient-opacity, rgba(0, 0, 0, 0.12));
}
.v-dialog > .v-overlay__content > .v-card,
.v-dialog > .v-overlay__content > form > .v-card {
display: flex;
flex-direction: column;
}
.v-dialog > .v-overlay__content > .v-card > .v-card-item,
.v-dialog > .v-overlay__content > form > .v-card > .v-card-item {
padding: 16px 24px;
}
.v-dialog > .v-overlay__content > .v-card > .v-card-item + .v-card-text,
.v-dialog > .v-overlay__content > form > .v-card > .v-card-item + .v-card-text {
padding-top: 0;
}
.v-dialog > .v-overlay__content > .v-card > .v-card-text,
.v-dialog > .v-overlay__content > form > .v-card > .v-card-text {
font-size: inherit;
letter-spacing: 0.03125em;
line-height: inherit;
padding: 16px 24px 24px;
}
.v-dialog > .v-overlay__content > .v-card > .v-card-actions,
.v-dialog > .v-overlay__content > form > .v-card > .v-card-actions {
justify-content: flex-end;
}
.v-dialog--fullscreen {
--v-scrollbar-offset: 0px;
}
.v-dialog--fullscreen > .v-overlay__content {
border-radius: 0;
margin: 0;
padding: 0;
width: 100%;
height: 100%;
max-width: 100%;
max-height: 100%;
overflow-y: auto;
top: 0;
left: 0;
}
.v-dialog--fullscreen > .v-overlay__content > .v-card,
.v-dialog--fullscreen > .v-overlay__content > .v-sheet,
.v-dialog--fullscreen > .v-overlay__content > form > .v-card,
.v-dialog--fullscreen > .v-overlay__content > form > .v-sheet {
min-height: 100%;
min-width: 100%;
border-radius: 0;
}
.v-dialog--scrollable > .v-overlay__content > form,
.v-dialog--scrollable > .v-overlay__content > form > .v-card {
max-height: 100%;
max-width: 100%;
}
.v-dialog--scrollable > .v-overlay__content,
.v-dialog--scrollable > .v-overlay__content > .v-card,
.v-dialog--scrollable > .v-overlay__content > form,
.v-dialog--scrollable > .v-overlay__content > form > .v-card {
display: flex;
flex: 1 1 100%;
flex-direction: column;
}
.v-dialog--scrollable > .v-overlay__content > .v-card > .v-card-text,
.v-dialog--scrollable > .v-overlay__content > form > .v-card > .v-card-text {
backface-visibility: hidden;
overflow-y: auto;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,111 @@
import { createVNode as _createVNode, mergeProps as _mergeProps } from "vue";
// Styles
import "./VDialog.css";
// Components
import { VDialogTransition } from "../transitions/index.js";
import { VDefaultsProvider } from "../VDefaultsProvider/index.js";
import { VOverlay } from "../VOverlay/index.js";
import { makeVOverlayProps } from "../VOverlay/VOverlay.js"; // Composables
import { forwardRefs } from "../../composables/forwardRefs.js";
import { useProxiedModel } from "../../composables/proxiedModel.js";
import { useScopeId } from "../../composables/scopeId.js"; // Utilities
import { mergeProps, nextTick, ref, watch } from 'vue';
import { genericComponent, omit, propsFactory, useRender } from "../../util/index.js"; // Types
export const makeVDialogProps = propsFactory({
fullscreen: Boolean,
scrollable: Boolean,
...omit(makeVOverlayProps({
captureFocus: true,
origin: 'center center',
scrollStrategy: 'block',
transition: {
component: VDialogTransition
},
zIndex: 2400,
retainFocus: true
}), ['disableInitialFocus'])
}, 'VDialog');
export const VDialog = genericComponent()({
name: 'VDialog',
props: makeVDialogProps(),
emits: {
'update:modelValue': value => true,
afterEnter: () => true,
afterLeave: () => true
},
setup(props, _ref) {
let {
emit,
slots
} = _ref;
const isActive = useProxiedModel(props, 'modelValue');
const {
scopeId
} = useScopeId();
const overlay = ref();
function onAfterEnter() {
emit('afterEnter');
if ((props.scrim || props.retainFocus) && overlay.value?.contentEl && !overlay.value.contentEl.contains(document.activeElement)) {
overlay.value.contentEl.focus({
preventScroll: true
});
}
}
function onAfterLeave() {
emit('afterLeave');
}
watch(isActive, async val => {
if (!val) {
await nextTick();
overlay.value.activatorEl?.focus({
preventScroll: true
});
}
});
useRender(() => {
const overlayProps = VOverlay.filterProps(props);
const activatorProps = mergeProps({
'aria-haspopup': 'dialog'
}, props.activatorProps);
const contentProps = mergeProps({
tabindex: -1
}, props.contentProps);
return _createVNode(VOverlay, _mergeProps({
"ref": overlay,
"class": ['v-dialog', {
'v-dialog--fullscreen': props.fullscreen,
'v-dialog--scrollable': props.scrollable
}, props.class],
"style": props.style
}, overlayProps, {
"modelValue": isActive.value,
"onUpdate:modelValue": $event => isActive.value = $event,
"aria-modal": "true",
"activatorProps": activatorProps,
"contentProps": contentProps,
"height": !props.fullscreen ? props.height : undefined,
"width": !props.fullscreen ? props.width : undefined,
"maxHeight": !props.fullscreen ? props.maxHeight : undefined,
"maxWidth": !props.fullscreen ? props.maxWidth : undefined,
"role": "dialog",
"onAfterEnter": onAfterEnter,
"onAfterLeave": onAfterLeave
}, scopeId), {
activator: slots.activator,
default: function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _createVNode(VDefaultsProvider, {
"root": "VDialog"
}, {
default: () => [slots.default?.(...args)]
});
}
});
});
return forwardRefs({}, overlay);
}
});
//# sourceMappingURL=VDialog.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,90 @@
@use '../../styles/tools'
@use './variables' as *
@include tools.layer('components')
.v-dialog
align-items: center
justify-content: center
margin: auto
> .v-overlay__content
max-height: calc(100% - #{$dialog-margin * 2})
width: calc(100% - #{$dialog-margin * 2})
max-width: calc(100% - #{$dialog-margin * 2})
margin: $dialog-margin
&,
> form
display: flex
flex-direction: column
min-height: 0
> .v-card,
> .v-sheet
--v-scrollbar-offset: 0px
border-radius: $dialog-border-radius
overflow-y: auto
flex: 1 1 100%
@include tools.elevation($dialog-elevation)
> .v-card
display: flex
flex-direction: column
> .v-card-item
padding: $dialog-card-header-padding
+ .v-card-text
padding-top: $dialog-card-header-text-padding-top
> .v-card-text
font-size: inherit
letter-spacing: $dialog-card-text-letter-spacing
line-height: inherit
padding: $dialog-card-text-padding
> .v-card-actions
justify-content: $dialog-card-actions-justify
.v-dialog--fullscreen
--v-scrollbar-offset: 0px
> .v-overlay__content
border-radius: 0
margin: 0
padding: 0
width: 100%
height: 100%
max-width: 100%
max-height: 100%
overflow-y: auto
top: 0
left: 0
&,
> form
> .v-card,
> .v-sheet
min-height: 100%
min-width: 100%
border-radius: 0
.v-dialog--scrollable > .v-overlay__content
> form
&,
> .v-card
max-height: 100%
max-width: 100%
&,
> form
&,
> .v-card
display: flex
flex: 1 1 100%
flex-direction: column
> .v-card > .v-card-text
backface-visibility: hidden
overflow-y: auto
@@ -0,0 +1,87 @@
import { createTextVNode as _createTextVNode, createElementVNode as _createElementVNode, createVNode as _createVNode } from "vue";
// Components
import { VDialog } from "../VDialog.js"; // Utilities
import { commands, render, screen, userEvent } from '@test';
import { nextTick, ref } from 'vue';
// Tests
describe('VDialog', () => {
it('should render correctly', async () => {
const model = ref(false);
render(() => _createElementVNode("div", null, [_createVNode(VDialog, {
"modelValue": model.value,
"onUpdate:modelValue": $event => model.value = $event,
"data-testid": "dialog"
}, {
default: () => [_createElementVNode("div", {
"data-testid": "content"
}, [_createTextVNode("Content")])]
})]));
expect(screen.queryByTestId('dialog')).toBeNull();
model.value = true;
await nextTick();
await expect(screen.findByTestId('dialog')).resolves.toBeVisible();
await expect.element(await screen.findByTestId('content')).toBeVisible();
await commands.click(0, 0);
await expect.poll(() => model.value).toBeFalsy();
await expect.poll(() => screen.queryByTestId('dialog')).toBeNull();
await expect.poll(() => screen.queryByTestId('content')).toBeNull();
});
it('should emit afterLeave', async () => {
const model = ref(true);
const onAfterLeave = vi.fn();
render(() => _createElementVNode("div", null, [_createVNode(VDialog, {
"modelValue": model.value,
"onUpdate:modelValue": $event => model.value = $event,
"onAfterLeave": onAfterLeave
}, {
default: () => [_createElementVNode("div", {
"data-test": "content"
}, [_createTextVNode("Content")])]
})]));
await commands.click(0, 0);
await expect.poll(() => onAfterLeave).toHaveBeenCalledTimes(1);
});
it('should focus on the last element when shift + tab key is pressed on the first element', async () => {
const model = ref(true);
render(() => _createElementVNode("div", null, [_createVNode(VDialog, {
"modelValue": model.value,
"onUpdate:modelValue": $event => model.value = $event,
"persistent": true
}, {
default: () => [_createElementVNode("div", null, [_createElementVNode("button", {
"data-testid": "first"
}, [_createTextVNode("First")]), _createElementVNode("button", {
"data-testid": "last"
}, [_createTextVNode("Last")])])]
})]));
const first = screen.getByCSS('button[data-testid="first"]');
const last = screen.getByCSS('button[data-testid="last"]');
first.focus();
await expect.poll(() => document.activeElement).toBe(first);
await userEvent.tab({
shift: true
});
await expect.poll(() => document.activeElement).toBe(last);
});
it('should focus on the first element when Tab key is pressed on the last element', async () => {
const model = ref(true);
render(() => _createElementVNode("div", null, [_createVNode(VDialog, {
"modelValue": model.value,
"onUpdate:modelValue": $event => model.value = $event
}, {
default: () => [_createElementVNode("div", null, [_createElementVNode("button", {
"data-testid": "first"
}, [_createTextVNode("First")]), _createElementVNode("button", {
"data-testid": "last"
}, [_createTextVNode("Last")])])]
})]));
const first = screen.getByCSS('button[data-testid="first"]');
const last = screen.getByCSS('button[data-testid="last"]');
last.focus();
await expect.poll(() => document.activeElement).toBe(last);
await userEvent.tab();
await expect.poll(() => document.activeElement).toBe(first);
});
});
//# sourceMappingURL=VDialog.spec.browser.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,14 @@
@use 'sass:map';
@use '../../styles/settings';
@use '../../styles/tools';
// Defaults
$dialog-elevation: 24 !default;
$dialog-border-radius: settings.$border-radius-root !default;
$dialog-margin: 24px !default;
$dialog-card-actions-justify: flex-end !default;
$dialog-card-header-padding: 16px 24px !default;
$dialog-card-header-text-padding-top: 0 !default;
$dialog-card-text-padding: 16px 24px 24px !default;
$dialog-card-text-letter-spacing: tools.map-deep-get(settings.$typography, 'body-1', 'letter-spacing') !default;
@@ -0,0 +1 @@
export { VDialog } from './VDialog.js';
@@ -0,0 +1,2 @@
export { VDialog } from "./VDialog.js";
//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
{"version":3,"file":"index.js","names":["VDialog"],"sources":["../../../src/components/VDialog/index.ts"],"sourcesContent":["export { VDialog } from './VDialog'\n"],"mappings":"SAASA,OAAO","ignoreList":[]}