srcdev-nuxt-components 9.1.49 → 9.1.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.json +2 -4
- package/.claude/settings.local.json +22 -2
- package/.claude/skills/components/card-core.md +205 -0
- package/.claude/skills/components/display-dialog.md +128 -0
- package/.claude/skills/components/page-hero-highlights.md +1 -1
- package/.claude/skills/components/page-row.md +157 -0
- package/.claude/skills/components/services-card-grid.md +4 -4
- package/.claude/skills/components/services-section-grid.md +4 -4
- package/.claude/skills/components/tab-navigation.md +222 -0
- package/.claude/skills/composable-dialog-controls.md +55 -43
- package/.claude/skills/index.md +5 -2
- package/app/components/01.atoms/card/CONSUMER-STYLING.md +175 -0
- package/app/components/01.atoms/card/CardCore.vue +48 -21
- package/app/components/01.atoms/display-dialog/CONSUMER-STYLING.md +163 -0
- package/app/components/01.atoms/display-dialog/DisplayDialog.vue +277 -0
- package/app/components/01.atoms/display-dialog/stories/DisplayDialog.stories.ts +177 -0
- package/app/components/01.atoms/display-dialog/tests/DisplayDialog.spec.ts +264 -0
- package/app/components/01.atoms/display-dialog/tests/__snapshots__/DisplayDialog.spec.ts.snap +18 -0
- package/app/components/01.atoms/page-row/CONSUMER-STYLING.md +90 -0
- package/app/components/01.atoms/page-row/PageRow.vue +115 -0
- package/app/components/01.atoms/page-row/stories/PageRow.stories.ts +311 -0
- package/app/components/01.atoms/page-row/tests/PageRow.spec.ts +191 -0
- package/app/components/02.molecules/navigation/tab-navigation/CONSUMER-STYLING.md +145 -0
- package/app/components/02.molecules/navigation/tab-navigation/TabNavigation.vue +21 -11
- package/app/components/02.molecules/navigation/tab-navigation/tests/__snapshots__/TabNavigation.spec.ts.snap +12 -6
- package/app/components/{forms/ui → 05.forms/form-field}/FormField.vue +12 -19
- package/app/components/{forms/ui → 05.forms/form-wrapper}/FormWrapper.vue +6 -6
- package/app/components/{forms → 05.forms}/input-button/InputButtonCore.vue +2 -0
- package/app/components/{forms → 05.forms}/input-button/stories/InputButtonCore.stories.ts +1 -1
- package/app/components/{forms → 05.forms}/input-text/InputTextCore.vue +73 -73
- package/app/components/{forms → 05.forms}/input-text/variants/InputTextAsNumberWithLabel.vue +29 -29
- package/app/components/carousels/CarouselBasic.vue +99 -99
- package/app/components/carousels/CarouselInfinite.vue +150 -150
- package/app/components/deep-expanding-menu/DeepExpandingMenu.vue +111 -111
- package/app/components/responsive-header/ResponsiveHeader.vue +250 -282
- package/app/components/test-storybook/TestStorybook.vue +16 -16
- package/app/composables/tests/useDialogControls.spec.ts +34 -64
- package/app/composables/useDialogControls.ts +19 -33
- package/app/composables/useFormControl.ts +0 -2
- package/app/layouts/default.vue +9 -7
- package/app/pages/auto-grid.vue +37 -20
- package/app/pages/banner-video.vue +2 -2
- package/app/pages/forms/examples/buttons/index.vue +189 -215
- package/app/pages/forms/examples/material/text-fields.vue +2 -2
- package/app/pages/grid-stack.vue +10 -10
- package/app/pages/index.vue +20 -20
- package/app/pages/samaritan.vue +4 -4
- package/app/pages/typography/hero-text.vue +6 -6
- package/app/pages/typography/index.vue +4 -4
- package/app/pages/typography/page-body.vue +4 -4
- package/app/pages/typography/page-heading.vue +4 -4
- package/app/pages/typography/page-link.vue +4 -4
- package/app/pages/ui/accordian.vue +4 -4
- package/app/pages/ui/anchor-scroll-tab-navigation.vue +77 -66
- package/app/pages/ui/anchor-scroll.vue +94 -70
- package/app/pages/ui/animated-svg-text.vue +4 -4
- package/app/pages/ui/block-decorators.vue +11 -11
- package/app/pages/ui/card-core.vue +9 -9
- package/app/pages/ui/carousel-basic.vue +4 -4
- package/app/pages/ui/carousel-flip.vue +2 -2
- package/app/pages/ui/carousel-infinite.vue +4 -4
- package/app/pages/ui/clipped-panels.vue +10 -10
- package/app/pages/ui/contact-section.vue +4 -4
- package/app/pages/ui/container-glow.vue +2 -3
- package/app/pages/ui/deep-expanding-menu.vue +138 -0
- package/app/pages/ui/display-avatar.vue +2 -2
- package/app/pages/ui/display-banner.vue +2 -2
- package/app/pages/ui/display-chip.vue +32 -25
- package/app/pages/ui/display-details.vue +6 -10
- package/app/pages/ui/display-dialog.vue +96 -131
- package/app/pages/ui/display-pill.vue +27 -33
- package/app/pages/ui/display-prompt.vue +4 -4
- package/app/pages/ui/display-toast.vue +2 -2
- package/app/pages/ui/expanding-panel.vue +12 -16
- package/app/pages/ui/glowing-border.vue +12 -12
- package/app/pages/ui/layout-grid-a.vue +6 -6
- package/app/pages/ui/layout-grid-b.vue +4 -4
- package/app/pages/ui/magnetic-navigation.vue +6 -6
- package/app/pages/ui/marquee-scroller.vue +2 -2
- package/app/pages/ui/mask-element.vue +2 -2
- package/app/pages/ui/masonry-columns.vue +4 -4
- package/app/pages/ui/masonry-grid-ordered-experiment.vue +4 -4
- package/app/pages/ui/masonry-grid-ordered.vue +4 -4
- package/app/pages/ui/masonry-grid-sorted.vue +4 -4
- package/app/pages/ui/masonry-grid.vue +4 -4
- package/app/pages/ui/navigation/navigation-horizontal.vue +12 -12
- package/app/pages/ui/navigation/tab-navigation.vue +493 -0
- package/app/pages/ui/page-row.vue +127 -0
- package/app/pages/ui/price-list.vue +4 -4
- package/app/pages/ui/profile-section.vue +4 -4
- package/app/pages/ui/qr-code/[componentName].vue +6 -6
- package/app/pages/ui/rotating-carousel.vue +16 -16
- package/app/pages/ui/scroll-reveal-image.vue +20 -20
- package/app/pages/ui/section-parallax.vue +7 -7
- package/app/pages/ui/services/colour-finder.vue +4 -4
- package/app/pages/ui/services/services-cards.vue +4 -4
- package/app/pages/ui/services/services-section/[slug].vue +4 -4
- package/app/pages/ui/services/services-sections-compact.vue +6 -6
- package/app/pages/ui/settings.vue +10 -10
- package/app/pages/ui/simple-grid.vue +2 -2
- package/app/pages/ui/slider-gallery.vue +5 -5
- package/app/pages/ui/tabs-y.vue +2 -3
- package/app/pages/ui/tabs.vue +6 -9
- package/app/pages/ui/tooltips.vue +9 -9
- package/app/pages/ui/wipe-away-vertical.vue +14 -14
- package/package.json +1 -1
- package/.claude/skills/components/layout-row.md +0 -239
- package/app/components/display-dialog/DisplayDialogCore.vue +0 -276
- package/app/components/display-dialog/variants/DisplayDialogConfirm.vue +0 -47
- package/app/components/display-dialog/variants/DisplayDialogScrollableContent.vue +0 -51
- package/app/components/forms/c12/utils.ts +0 -14
- package/app/components/layout-row/LayoutRow.vue +0 -171
- package/app/components/layout-row/stories/LayoutRow.stories.ts +0 -528
- package/app/pages/ui/layout-row.vue +0 -139
- /package/app/components/{forms → 05.forms}/form-errors/InputError.vue +0 -0
- /package/app/components/{forms → 05.forms}/form-errors/tests/InputError.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/form-fieldset/FormFieldset.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-secondary-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-secondary-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-secondary-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-tertiary-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-tertiary-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-icons-tertiary-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-primary-pending-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-primary-pending-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-primary-pending-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-secondary-pill-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-secondary-pill-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-secondary-pill-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-tertiary-readonly-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-tertiary-readonly-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/combo-tertiary-readonly-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-default-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-default-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-default-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-error-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-error-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-error-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-success-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-success-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-success-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-warning-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-warning-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-theme-warning-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-primary-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-primary-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-primary-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-secondary-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-secondary-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-secondary-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-tertiary-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-tertiary-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-variant-tertiary-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/default-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/nuxt-icon-only-component-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/nuxt-icon-only-component-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/nuxt-icon-only-component-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pending-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pending-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pending-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pill-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pill-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-pill-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-readonly-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-readonly-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/state-readonly-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/with-both-nuxt-icon-components-chromium-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/with-both-nuxt-icon-components-firefox-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/playwright/input-button-core.playwright.ts-snapshots/with-both-nuxt-icon-components-webkit-darwin.png +0 -0
- /package/app/components/{forms → 05.forms}/input-button/tests/InputButtonCore.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-button/tests/__snapshots__/InputButtonCore.spec.ts.snap +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox/MultipleCheckboxes.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox/SingleCheckbox.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox/tests/MultipleCheckboxes.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox/tests/data/tags.json +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox-radio/InputCheckboxRadioButton.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox-radio/InputCheckboxRadioCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox-radio/InputCheckboxRadioWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-checkbox-radio/tests/InputCheckboxRadioCore.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-copy/InputCopyCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-copy/stories/InputCopyCore.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-copy/tests/InputCopyCore.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-copy/tests/__snapshots__/InputCopyCore.spec.ts.snap +0 -0
- /package/app/components/{forms → 05.forms}/input-description/InputDescription.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-description/tests/InputDescription.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-label/InputLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-label/tests/InputLabel.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-number/InputNumberCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-number/variants/InputNumberDefault.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-radio/MultipleRadiobuttons.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-radio/tests/MultipleRadioButtons.spec.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-radio/tests/data/tags.json +0 -0
- /package/app/components/{forms → 05.forms}/input-range/InputRangeCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-range/variants/InputRangeDefault.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-range-fancy/InputRangeFancyCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-range-fancy/InputRangeFancyWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-select/InputSelectCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-select/variants/InputSelectWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-text/stories/InputPasswordWithLabel.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-text/stories/InputTextAsNumberWithLabel.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-text/stories/InputTextCore.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-text/stories/InputTextWithLabel.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-text/variants/InputPasswordWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-text/variants/InputTextWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-textarea/InputTextareaCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/input-textarea/stories/InputTextareaCore.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-textarea/stories/InputTextareaWithLabel.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/input-textarea/variants/InputTextareaWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/pending-effect/PendingEffect.vue +0 -0
- /package/app/components/{forms → 05.forms}/toggle-switch/ToggleSwitchCore.vue +0 -0
- /package/app/components/{forms → 05.forms}/toggle-switch/stories/ToggleSwitchCore.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/toggle-switch/stories/ToggleSwitchWithLabel.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/toggle-switch/stories/ToggleSwitchWithLabelInline.stories.ts +0 -0
- /package/app/components/{forms → 05.forms}/toggle-switch/variants/ToggleSwitchWithLabel.vue +0 -0
- /package/app/components/{forms → 05.forms}/toggle-switch/variants/ToggleSwitchWithLabelInline.vue +0 -0
- /package/app/components/{forms → 05.forms}/triple-toggle-switch/TripleToggleSwitchCore.vue +0 -0
- /package/app/{components/forms/c12/prop-validators/index.ts → utils/prop-validators.ts} +0 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { nextTick } from "vue";
|
|
3
|
+
import { mountSuspended } from "@nuxt/test-utils/runtime";
|
|
4
|
+
import DisplayDialog from "../DisplayDialog.vue";
|
|
5
|
+
|
|
6
|
+
vi.mock("focus-trap-vue", () => ({
|
|
7
|
+
FocusTrap: {
|
|
8
|
+
name: "FocusTrap",
|
|
9
|
+
props: ["active", "escapeDeactivates", "clickOutsideDeactivates"],
|
|
10
|
+
emits: ["update:active", "deactivate"],
|
|
11
|
+
template: "<slot />",
|
|
12
|
+
},
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
describe("DisplayDialog", () => {
|
|
16
|
+
// ─── Mount ────────────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
it("mounts without error", async () => {
|
|
19
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
20
|
+
props: { dataDialogId: "test" },
|
|
21
|
+
});
|
|
22
|
+
expect(wrapper.vm).toBeTruthy();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// ─── Snapshot ─────────────────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
it("renders correct HTML structure with all slots", async () => {
|
|
28
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
29
|
+
props: { dataDialogId: "test", modelValue: true },
|
|
30
|
+
slots: {
|
|
31
|
+
dialogTitle: "<p>Title</p>",
|
|
32
|
+
dialogContent: "<p>Content</p>",
|
|
33
|
+
actionButtonLeft: "<button>Cancel</button>",
|
|
34
|
+
actionButtonRight: "<button>Confirm</button>",
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
expect(wrapper.html()).toMatchSnapshot();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// ─── Root element ─────────────────────────────────────────────────────────
|
|
41
|
+
|
|
42
|
+
it("renders as <dialog>", async () => {
|
|
43
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
44
|
+
props: { dataDialogId: "test" },
|
|
45
|
+
});
|
|
46
|
+
expect(wrapper.element.tagName).toBe("DIALOG");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("always has the display-dialog class", async () => {
|
|
50
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
51
|
+
props: { dataDialogId: "test" },
|
|
52
|
+
});
|
|
53
|
+
expect(wrapper.classes()).toContain("display-dialog");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// ─── data-dialog-id ───────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
it("sets data-dialog-id attribute from prop", async () => {
|
|
59
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
60
|
+
props: { dataDialogId: "my-dialog" },
|
|
61
|
+
});
|
|
62
|
+
expect(wrapper.attributes("data-dialog-id")).toBe("my-dialog");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// ─── open attribute ───────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
it("sets [open] attribute when modelValue is true", async () => {
|
|
68
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
69
|
+
props: { dataDialogId: "test", modelValue: true },
|
|
70
|
+
});
|
|
71
|
+
expect(wrapper.attributes("open")).toBeDefined();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("omits [open] attribute when modelValue is false", async () => {
|
|
75
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
76
|
+
props: { dataDialogId: "test", modelValue: false },
|
|
77
|
+
});
|
|
78
|
+
expect(wrapper.attributes("open")).toBeUndefined();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// ─── role ─────────────────────────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
it("has role='dialog' by default", async () => {
|
|
84
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
85
|
+
props: { dataDialogId: "test" },
|
|
86
|
+
});
|
|
87
|
+
expect(wrapper.attributes("role")).toBe("dialog");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it.each(["dialog", "modal", "confirm", "fullscreen"] as const)(
|
|
91
|
+
"has role='dialog' for variant='%s'",
|
|
92
|
+
async (variant) => {
|
|
93
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
94
|
+
props: { dataDialogId: "test", variant },
|
|
95
|
+
});
|
|
96
|
+
expect(wrapper.attributes("role")).toBe("dialog");
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
it("has role='alertdialog' for variant='alert'", async () => {
|
|
101
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
102
|
+
props: { dataDialogId: "test", variant: "alert" },
|
|
103
|
+
});
|
|
104
|
+
expect(wrapper.attributes("role")).toBe("alertdialog");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// ─── Variant class on .inner ──────────────────────────────────────────────
|
|
108
|
+
|
|
109
|
+
it("applies 'dialog' class to .inner by default", async () => {
|
|
110
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
111
|
+
props: { dataDialogId: "test" },
|
|
112
|
+
});
|
|
113
|
+
expect(wrapper.find(".inner").classes()).toContain("dialog");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it.each(["dialog", "modal", "confirm", "alert", "fullscreen"] as const)(
|
|
117
|
+
"applies '%s' class to .inner",
|
|
118
|
+
async (variant) => {
|
|
119
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
120
|
+
props: { dataDialogId: "test", variant },
|
|
121
|
+
});
|
|
122
|
+
expect(wrapper.find(".inner").classes()).toContain(variant);
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
// ─── Slots ────────────────────────────────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
it("renders dialogTitle slot in .col-left", async () => {
|
|
129
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
130
|
+
props: { dataDialogId: "test" },
|
|
131
|
+
slots: { dialogTitle: "<p>My Title</p>" },
|
|
132
|
+
});
|
|
133
|
+
expect(wrapper.find(".col-left").text()).toBe("My Title");
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("omits .col-left when dialogTitle slot is not provided", async () => {
|
|
137
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
138
|
+
props: { dataDialogId: "test" },
|
|
139
|
+
});
|
|
140
|
+
expect(wrapper.find(".col-left").exists()).toBe(false);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("renders dialogContent slot in .dialog-content", async () => {
|
|
144
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
145
|
+
props: { dataDialogId: "test" },
|
|
146
|
+
slots: { dialogContent: "<p>Content</p>" },
|
|
147
|
+
});
|
|
148
|
+
expect(wrapper.find(".dialog-content").text()).toBe("Content");
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("omits .dialog-content when dialogContent slot is not provided", async () => {
|
|
152
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
153
|
+
props: { dataDialogId: "test" },
|
|
154
|
+
});
|
|
155
|
+
expect(wrapper.find(".dialog-content").exists()).toBe(false);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("renders .footer when actionButtonLeft slot is provided", async () => {
|
|
159
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
160
|
+
props: { dataDialogId: "test" },
|
|
161
|
+
slots: { actionButtonLeft: "<button>Cancel</button>" },
|
|
162
|
+
});
|
|
163
|
+
expect(wrapper.find(".footer").exists()).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("renders .footer when actionButtonRight slot is provided", async () => {
|
|
167
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
168
|
+
props: { dataDialogId: "test" },
|
|
169
|
+
slots: { actionButtonRight: "<button>Confirm</button>" },
|
|
170
|
+
});
|
|
171
|
+
expect(wrapper.find(".footer").exists()).toBe(true);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("omits .footer when neither action button slot is provided", async () => {
|
|
175
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
176
|
+
props: { dataDialogId: "test" },
|
|
177
|
+
});
|
|
178
|
+
expect(wrapper.find(".footer").exists()).toBe(false);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("renders both action button slots inside .footer", async () => {
|
|
182
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
183
|
+
props: { dataDialogId: "test" },
|
|
184
|
+
slots: {
|
|
185
|
+
actionButtonLeft: "<button>Cancel</button>",
|
|
186
|
+
actionButtonRight: "<button>Confirm</button>",
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
expect(wrapper.find(".footer").text()).toContain("Cancel");
|
|
190
|
+
expect(wrapper.find(".footer").text()).toContain("Confirm");
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// ─── allowContentScroll ───────────────────────────────────────────────────
|
|
194
|
+
|
|
195
|
+
it("does not apply allow-content-scroll class by default", async () => {
|
|
196
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
197
|
+
props: { dataDialogId: "test" },
|
|
198
|
+
slots: { dialogContent: "<p>Content</p>" },
|
|
199
|
+
});
|
|
200
|
+
expect(wrapper.find(".dialog-content").classes()).not.toContain("allow-content-scroll");
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("applies allow-content-scroll class when allowContentScroll=true", async () => {
|
|
204
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
205
|
+
props: { dataDialogId: "test", allowContentScroll: true },
|
|
206
|
+
slots: { dialogContent: "<p>Content</p>" },
|
|
207
|
+
});
|
|
208
|
+
expect(wrapper.find(".dialog-content").classes()).toContain("allow-content-scroll");
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// ─── Close button ─────────────────────────────────────────────────────────
|
|
212
|
+
|
|
213
|
+
it("close button emits update:modelValue=false", async () => {
|
|
214
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
215
|
+
props: { dataDialogId: "test", modelValue: true },
|
|
216
|
+
});
|
|
217
|
+
await wrapper.find('[data-test-id="display-dialog-header-close"]').trigger("click");
|
|
218
|
+
expect(wrapper.emitted("update:modelValue")?.[0]).toEqual([false]);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// ─── styleClassPassthrough ────────────────────────────────────────────────
|
|
222
|
+
|
|
223
|
+
it("applies a styleClassPassthrough string", async () => {
|
|
224
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
225
|
+
props: { dataDialogId: "test", styleClassPassthrough: "my-class" },
|
|
226
|
+
});
|
|
227
|
+
expect(wrapper.classes()).toContain("my-class");
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("applies multiple styleClassPassthrough classes from an array", async () => {
|
|
231
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
232
|
+
props: { dataDialogId: "test", styleClassPassthrough: ["class-a", "class-b"] },
|
|
233
|
+
});
|
|
234
|
+
expect(wrapper.classes()).toContain("class-a");
|
|
235
|
+
expect(wrapper.classes()).toContain("class-b");
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// ─── Body viewport lock ───────────────────────────────────────────────────
|
|
239
|
+
|
|
240
|
+
it("adds lock class to body on mount when lockViewport=true", async () => {
|
|
241
|
+
await mountSuspended(DisplayDialog, {
|
|
242
|
+
props: { dataDialogId: "test", lockViewport: true },
|
|
243
|
+
});
|
|
244
|
+
expect(document.body.classList.contains("lock")).toBe(true);
|
|
245
|
+
document.body.classList.remove("lock");
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("does not add lock class to body when lockViewport=false", async () => {
|
|
249
|
+
await mountSuspended(DisplayDialog, {
|
|
250
|
+
props: { dataDialogId: "test", lockViewport: false },
|
|
251
|
+
});
|
|
252
|
+
expect(document.body.classList.contains("lock")).toBe(false);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("removes lock class from body when close button is clicked", async () => {
|
|
256
|
+
document.body.classList.add("lock");
|
|
257
|
+
const wrapper = await mountSuspended(DisplayDialog, {
|
|
258
|
+
props: { dataDialogId: "test", modelValue: true, lockViewport: true },
|
|
259
|
+
});
|
|
260
|
+
await wrapper.find('[data-test-id="display-dialog-header-close"]').trigger("click");
|
|
261
|
+
await nextTick();
|
|
262
|
+
expect(document.body.classList.contains("lock")).toBe(false);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`DisplayDialog > renders correct HTML structure with all slots 1`] = `
|
|
4
|
+
"<dialog class="display-dialog" role="dialog" align-dialog="center" justify-dialog="center" open="" data-dialog-id="test">
|
|
5
|
+
<div class="inner dialog">
|
|
6
|
+
<div class="header">
|
|
7
|
+
<div class="col-left">
|
|
8
|
+
<p>Title</p>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="col-right"><button data-test-id="display-dialog-header-close" class="display-prompt-action"><span class="iconify i-bitcoin-icons:cross-filled icon" aria-hidden="true"></span><span class="sr-only">Close</span></button></div>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="dialog-content">
|
|
13
|
+
<p>Content</p>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="footer"><button>Cancel</button><button>Confirm</button></div>
|
|
16
|
+
</div>
|
|
17
|
+
</dialog>"
|
|
18
|
+
`;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# PageRow — Consumer Styling Guide
|
|
2
|
+
|
|
3
|
+
## Public token API
|
|
4
|
+
|
|
5
|
+
All `--page-row-*` tokens are the stable override surface. Set them at any scope (global, page,
|
|
6
|
+
or instance) without touching the component itself.
|
|
7
|
+
|
|
8
|
+
| Token | Default | Controls |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| `--page-row-minimum-content-padding` | `1rem` | Minimum gutter on each side at narrow viewports |
|
|
11
|
+
| `--page-row-popout-max-width` | `1400px` | Maximum width of the `popout` column track |
|
|
12
|
+
| `--page-row-content-max-width` | `1064px` | Maximum width of the `content` column track |
|
|
13
|
+
| `--page-row-inset-content-max-width` | `840px` | Maximum width of the `inset-content` column track |
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Global theming — app-level CSS file
|
|
18
|
+
|
|
19
|
+
Create `assets/styles/setup/07.components/page-row.css` in the consuming app and set tokens on
|
|
20
|
+
`:root`. These values apply to every `PageRow` instance across the site.
|
|
21
|
+
|
|
22
|
+
```css
|
|
23
|
+
/* assets/styles/setup/07.components/page-row.css */
|
|
24
|
+
:root {
|
|
25
|
+
--page-row-minimum-content-padding: 1.6rem;
|
|
26
|
+
--page-row-popout-max-width: 1280px;
|
|
27
|
+
--page-row-content-max-width: 960px;
|
|
28
|
+
--page-row-inset-content-max-width: 720px;
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Page-scoped overrides
|
|
35
|
+
|
|
36
|
+
Override track widths for a specific page by scoping tokens under the page wrapper. No `:deep()`
|
|
37
|
+
is required (component styles are unscoped).
|
|
38
|
+
|
|
39
|
+
```css
|
|
40
|
+
/* In the consuming page's unscoped <style> block */
|
|
41
|
+
.landing-page {
|
|
42
|
+
.page-row {
|
|
43
|
+
--page-row-content-max-width: 800px;
|
|
44
|
+
--page-row-minimum-content-padding: 2.4rem;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Per-instance overrides via inline style
|
|
52
|
+
|
|
53
|
+
```vue
|
|
54
|
+
<PageRow
|
|
55
|
+
variant="content"
|
|
56
|
+
style="--page-row-content-max-width: 720px;"
|
|
57
|
+
>
|
|
58
|
+
...
|
|
59
|
+
</PageRow>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Per-instance overrides via styleClassPassthrough
|
|
65
|
+
|
|
66
|
+
```vue
|
|
67
|
+
<PageRow variant="content" :style-class-passthrough="['narrow']">
|
|
68
|
+
...
|
|
69
|
+
</PageRow>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```css
|
|
73
|
+
.page-row {
|
|
74
|
+
&.narrow {
|
|
75
|
+
--page-row-content-max-width: 720px;
|
|
76
|
+
--page-row-minimum-content-padding: 2rem;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Notes
|
|
84
|
+
|
|
85
|
+
- Track widths are derived from the four tokens using `calc()` — changing one token shifts all
|
|
86
|
+
related tracks proportionally.
|
|
87
|
+
- `--page-row-minimum-content-padding` controls how close content gets to the viewport edge on
|
|
88
|
+
narrow screens; it also sets the outer `full` gutter minimum.
|
|
89
|
+
- The component applies no padding, margin, or background — those are always set by the consuming
|
|
90
|
+
app on the PageRow element or its children.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<component
|
|
3
|
+
:is="tag"
|
|
4
|
+
:id
|
|
5
|
+
class="page-row"
|
|
6
|
+
:class="[elementClasses, variant]"
|
|
7
|
+
:data-align="align || undefined"
|
|
8
|
+
:aria-labelledby="ariaLabelledby"
|
|
9
|
+
>
|
|
10
|
+
<slot :heading-id="headingId"></slot>
|
|
11
|
+
</component>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
interface Props {
|
|
16
|
+
tag?: "div" | "section" | "article" | "header" | "footer" | "main" | "nav";
|
|
17
|
+
variant?: "full" | "popout" | "content" | "inset-content";
|
|
18
|
+
align?: "start" | "end";
|
|
19
|
+
id?: string | null;
|
|
20
|
+
styleClassPassthrough?: string | string[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
24
|
+
tag: "div",
|
|
25
|
+
variant: "content",
|
|
26
|
+
align: undefined,
|
|
27
|
+
id: null,
|
|
28
|
+
styleClassPassthrough: () => [],
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
|
|
32
|
+
const { headingId, ariaLabelledby } = useAriaLabelledById(props.tag);
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<style lang="css">
|
|
36
|
+
@layer components {
|
|
37
|
+
/*
|
|
38
|
+
* Page layout grid — https://layout-breakouts-builder.vercel.app
|
|
39
|
+
* Each .page-row is both a CSS grid container and a grid item when nested.
|
|
40
|
+
* Direct children default to the content column; nest a .page-row.{variant}
|
|
41
|
+
* to break out to a wider or narrower track.
|
|
42
|
+
*/
|
|
43
|
+
.page-row {
|
|
44
|
+
--_minimum-content-padding: var(--page-row-minimum-content-padding, 1rem);
|
|
45
|
+
--_popout-max-width: var(--page-row-popout-max-width, 1400px);
|
|
46
|
+
--_content-max-width: var(--page-row-content-max-width, 1064px);
|
|
47
|
+
--_inset-content-max-width: var(--page-row-inset-content-max-width, 840px);
|
|
48
|
+
|
|
49
|
+
--full: minmax(var(--_minimum-content-padding), 1fr);
|
|
50
|
+
--popout: minmax(0, calc((var(--_popout-max-width) - var(--_content-max-width)) * 0.5));
|
|
51
|
+
--content: minmax(0, calc((var(--_content-max-width) - var(--_inset-content-max-width)) * 0.5));
|
|
52
|
+
--inset-content: min(var(--_inset-content-max-width), 100% - var(--_minimum-content-padding) * 2);
|
|
53
|
+
|
|
54
|
+
display: grid;
|
|
55
|
+
grid-template-columns:
|
|
56
|
+
[full-start]
|
|
57
|
+
var(--full)
|
|
58
|
+
[popout-start]
|
|
59
|
+
var(--popout)
|
|
60
|
+
[content-start]
|
|
61
|
+
var(--content)
|
|
62
|
+
[inset-content-start]
|
|
63
|
+
var(--inset-content)
|
|
64
|
+
[inset-content-end]
|
|
65
|
+
var(--content)
|
|
66
|
+
[content-end]
|
|
67
|
+
var(--popout)
|
|
68
|
+
[popout-end]
|
|
69
|
+
var(--full)
|
|
70
|
+
[full-end];
|
|
71
|
+
|
|
72
|
+
container-type: inline-size;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* All direct children default to the content column */
|
|
76
|
+
.page-row > * {
|
|
77
|
+
grid-column: content;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
* Variant propagation: a page-row's variant also sets the default column
|
|
82
|
+
* for its direct non-PageRow children. This allows variant="full" to make
|
|
83
|
+
* its own children span full width, not just control placement when nested.
|
|
84
|
+
* Specificity (0,2,0) — nested .page-row variant overrides below win at (0,3,0).
|
|
85
|
+
*/
|
|
86
|
+
.page-row.full > * { grid-column: full; }
|
|
87
|
+
.page-row.popout > * { grid-column: popout; }
|
|
88
|
+
.page-row.inset-content > * { grid-column: inset-content; }
|
|
89
|
+
|
|
90
|
+
/* Nested page-rows: symmetric placement by variant class */
|
|
91
|
+
.page-row > .page-row {
|
|
92
|
+
&.full { grid-column: full; }
|
|
93
|
+
&.popout { grid-column: popout; }
|
|
94
|
+
&.content { grid-column: content; }
|
|
95
|
+
&.inset-content { grid-column: inset-content; }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/*
|
|
99
|
+
* align="start": bleeds to the left (full-start) edge, stops at the variant's end line.
|
|
100
|
+
* align="end": starts at the variant's start line, bleeds to the right (full-end) edge.
|
|
101
|
+
* Specificity (0,4,0) beats the symmetric rules above at (0,3,0).
|
|
102
|
+
*/
|
|
103
|
+
.page-row > .page-row[data-align="start"] {
|
|
104
|
+
&.popout { grid-column: full-start / popout-end; }
|
|
105
|
+
&.content { grid-column: full-start / content-end; }
|
|
106
|
+
&.inset-content { grid-column: full-start / inset-content-end; }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.page-row > .page-row[data-align="end"] {
|
|
110
|
+
&.popout { grid-column: popout-start / full-end; }
|
|
111
|
+
&.content { grid-column: content-start / full-end; }
|
|
112
|
+
&.inset-content { grid-column: inset-content-start / full-end; }
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
</style>
|