Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: new FPageExpandablePanel (refs SFKUI-6500) #205

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 15 additions & 8 deletions etc/vue.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -9234,6 +9234,13 @@ rotate: string;
}, {}, string, ComponentProvideOptions, true, {}, any>;
}, {}, string, ComponentProvideOptions, true, {}, any>;

// Warning: (ae-forgotten-export) The symbol "__VLS_WithTemplateSlots_3" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "__VLS_component_3" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "__VLS_TemplateResult_3" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
export const FPageExpandablePanel: __VLS_WithTemplateSlots_3<typeof __VLS_component_3, __VLS_TemplateResult_3["slots"]>;

// @public (undocumented)
export const FPageHeader: DefineComponent<ExtractPropTypes< {
skipLink: {
Expand Down Expand Up @@ -9281,12 +9288,12 @@ href: string;
}, {}, {}, {}, string, ComponentProvideOptions, true, {}, any>;
}, {}, string, ComponentProvideOptions, true, {}, any>;

// Warning: (ae-forgotten-export) The symbol "__VLS_WithTemplateSlots_3" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "__VLS_component_3" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "__VLS_TemplateResult_3" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "__VLS_WithTemplateSlots_4" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "__VLS_component_4" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "__VLS_TemplateResult_4" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
export const FPageLayout: __VLS_WithTemplateSlots_3<typeof __VLS_component_3, __VLS_TemplateResult_3["slots"]>;
export const FPageLayout: __VLS_WithTemplateSlots_4<typeof __VLS_component_4, __VLS_TemplateResult_4["slots"]>;

// @public (undocumented)
export const FPercentTextField: DefineComponent<ExtractPropTypes< {
Expand Down Expand Up @@ -15114,12 +15121,12 @@ export interface IPopupErrorData {
teleportDisabled: boolean;
}

// Warning: (ae-forgotten-export) The symbol "__VLS_WithTemplateSlots_4" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "__VLS_component_4" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "__VLS_TemplateResult_4" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "__VLS_WithTemplateSlots_5" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "__VLS_component_5" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "__VLS_TemplateResult_5" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
export const IPopupListbox: __VLS_WithTemplateSlots_4<typeof __VLS_component_4, __VLS_TemplateResult_4["slots"]>;
export const IPopupListbox: __VLS_WithTemplateSlots_5<typeof __VLS_component_5, __VLS_TemplateResult_5["slots"]>;

// @public (undocumented)
export const IPopupMenu: DefineComponent<ExtractPropTypes< {
Expand Down
86 changes: 85 additions & 1 deletion internal/vue-sandbox/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,87 @@
<script setup lang="ts">
import { FPageExpandablePanel, FPageLayout } from "@fkui/vue";
</script>

<template>
<router-view />
<f-page-layout layout="three-column">
<template #header> [header] </template>
<template #left>
<f-page-expandable-panel>
<template #header> [panel header] </template>
<template #default>
<p>[panel content]</p>
<p>[panel content]</p>
<p>[panel content]</p>
</template>
<template #footer> [panel footer] </template>
</f-page-expandable-panel>
</template>
<template #right>
<f-page-expandable-panel>
<template #header> [panel header] </template>
<template #default>
<p>[panel content]</p>
<p>[panel content]</p>
<p>[panel content]</p>
</template>
<template #footer> [panel footer] </template>
</f-page-expandable-panel>
</template>
<template #content>
<!-- [html-validate-disable-next no-inline-style -- for testing only]-->
<div style="padding: 0.5rem">
<h1>Lorem ipsum dolor sit amet</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque dictum mauris non urna faucibus
porta. Aenean euismod rutrum finibus. Morbi ultricies, augue ut volutpat dictum, nisi quam consequat
mauris, lacinia aliquam lacus ante et arcu. In non justo dui. Ut dui leo, commodo ut odio at,
ultrices imperdiet enim. Fusce dolor lacus, gravida eget dui sed, dictum elementum magna. Quisque
blandit egestas ultricies. Cras ultricies eget eros ultrices blandit. Interdum et malesuada fames ac
ante ipsum primis in faucibus. Praesent in justo ultrices nunc efficitur mattis at vel lorem.
Maecenas rhoncus felis tincidunt dui faucibus, nec rhoncus tellus mollis. Phasellus vitae magna
turpis. Etiam in mattis mi. Duis at justo finibus, tristique lacus nec, lobortis dui.
</p>
<p>
Ut placerat consectetur pretium. Proin luctus neque vitae consequat pellentesque. Aliquam arcu arcu,
auctor ac ipsum aliquet, bibendum pretium est. Integer sit amet mattis dolor, quis volutpat justo.
Curabitur eu tempus nibh. Aliquam erat volutpat. Phasellus tincidunt suscipit nulla a viverra. Cras
nec felis ut dolor malesuada congue vitae a neque.
</p>
<p>
Vivamus tortor quam, dignissim at aliquet ut, tristique id orci. Nulla fringilla nulla est, quis
tempor risus fermentum non. Ut id ullamcorper tellus. Donec lacinia condimentum neque, eget varius
mi convallis vitae. Nullam ante turpis, egestas ac nibh ut, pretium rutrum metus. Aenean non tellus
nulla. Duis ornare tempor tristique. Etiam tempus nec nisl quis varius. Pellentesque lacinia a
sapien quis ultricies.
</p>
<p>
Donec ut egestas dui. Donec purus nulla, aliquam sed auctor vitae, porta non quam. Nam eros arcu,
tempus a nisi ac, scelerisque cursus diam. Mauris sodales magna at diam semper efficitur. Ut
hendrerit urna vitae massa bibendum pretium. Proin bibendum tortor in nulla maximus, eget laoreet
ipsum ornare. Mauris rutrum massa vel enim imperdiet consequat. Phasellus convallis nunc est, vel
tristique mi sollicitudin sit amet. Aliquam auctor id metus nec interdum. Nam eget sem sed nunc
egestas pretium.
</p>
<p>
Interdum et malesuada fames ac ante ipsum primis in faucibus. Fusce vitae quam sapien. Etiam gravida
accumsan enim. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus
mus. In lobortis lobortis pharetra. Curabitur diam sem, posuere nec iaculis vel, convallis sed
augue. Etiam vel urna id lectus lacinia volutpat. Phasellus nec bibendum ex. Nullam magna nibh,
ultrices sit amet felis fringilla, iaculis ultricies justo. Nulla viverra aliquet turpis, quis
hendrerit sapien elementum at. Nunc bibendum in nisl sed blandit. Integer tincidunt augue nec arcu
lacinia tristique. Aenean id mauris venenatis, blandit ligula a, consequat ante. Fusce aliquam mi
sed rutrum posuere. Morbi congue lorem est, elementum suscipit mi ullamcorper vitae. Quisque non
iaculis leo.
</p>
</div>
</template>
<template #footer> [footer] </template>
</f-page-layout>
</template>

<style>
body {
margin: 0;
padding: 0;
}
</style>
1 change: 1 addition & 0 deletions internal/vue-sandbox/src/local.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@use "@fkui/theme-default";
@use "@fkui/design";
@use "@fkui/design/lib/fonts.css";
@use "@fkui/vue/style.css";
4 changes: 4 additions & 0 deletions packages/vue/htmlvalidate/elements/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,10 @@ module.exports = defineMetadata({
},
},

"f-page-expandable-panel": {
flow: true,
},

"f-progressbar": {
flow: true,
requiredAttributes: ["aria-label"],
Expand Down
1 change: 1 addition & 0 deletions packages/vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"types": "./dist/types/cypress.d.ts",
"default": "./dist/cjs/cypress.js"
},
"./style.css": "./dist/esm/vue.css",
"./htmlvalidate": "./htmlvalidate/index.cjs",
"./htmlvalidate/cypress": "./htmlvalidate/cypress.js",
"./package.json": "./package.json",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<script lang="ts">
export default defineComponent({
name: "FPageClosablePanel",
});
</script>

<script setup lang="ts" generic="T">
import { computed, defineComponent, onUnmounted, ref, useTemplateRef } from "vue";

Check failure on line 8 in packages/vue/src/components/FPageClosablePanel/FPageClosablePanel.vue

View workflow job for this annotation

GitHub Actions / Lint

'ref' is defined but never used
import { FIcon } from "../FIcon";
import { useAreaData } from "../FPageLayout/use-area-data";
import { createClosablePanel } from "./use-panel";

const root = useTemplateRef("root");
const { attach } = useAreaData(root);

const props = defineProps<{
name: string;
}>();

const panel = createClosablePanel<T>(props.name);

const attachClass = computed(() => {
switch (attach.value) {
case "left":
return "attach-left";
case "right":
return "attach-right";
}
return undefined;
});

onUnmounted(() => {
panel.destroy();
});

function onToggle(): void {
panel.close();
}

function onClose(reason?: string): void {
if (panel.callback.value) {
panel.callback.value({ item: panel.item.value!, reason: reason ?? "close" });

Check failure on line 42 in packages/vue/src/components/FPageClosablePanel/FPageClosablePanel.vue

View workflow job for this annotation

GitHub Actions / Lint

Forbidden non-null assertion
panel.close();
}
}
</script>

<template>
<div v-if="panel.item.value" ref="root" class="panel__wrapper">
<div class="panel panel--closable" :class="[attachClass]">
<div class="panel__header">
<div class="panel__title">
<slot name="header" v-bind="{ item: panel.item.value, close: onClose }"></slot>
</div>
<div class="panel__collapse">
<button type="button" @click="onToggle()">
<f-icon name="close"> <title>Stäng</title> </f-icon>
</button>
</div>
</div>
<div class="panel__content">
<slot name="default" v-bind="{ item: panel.item.value, close: onClose }"></slot>
</div>
<div class="panel__footer">
<slot name="footer"></slot>
</div>
</div>
</div>
</template>

<style scoped>
.panel__wrapper {
flex-grow: 1;
display: flex;
}

.panel {
flex-grow: 1;
background: lightskyblue;

display: flex;
flex-direction: column;
padding: 0.5rem;
gap: 0.5rem;
min-width: 25ch;

@media (width < 640px) {
position: absolute;
top: 0;
bottom: 0;
z-index: 1;

&.attach-left {
left: 0;
}

&.attach-right {
right: 0;
}
}
}

.panel__header {
flex: 0 0 auto;
display: flex;
gap: 0.5rem;
align-items: center;
justify-content: center;

.attach-left & {
flex-direction: row;
}

.attach-right & {
flex-direction: row-reverse;
}
}

.panel__title {
flex: 1 0 auto;
font-weight: 600;
font-size: 1.2em;
}

.panel__content {
flex: 1 0 auto;
}

.panel__footer {
flex: 0 0 auto;
}

button {
appearance: none;
padding: 0;
line-height: 1;
background: transparent;
border: 0;
cursor: pointer;
}
</style>
1 change: 1 addition & 0 deletions packages/vue/src/components/FPageClosablePanel/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as FPageClosablePanel } from "./FPageClosablePanel.vue";
57 changes: 57 additions & 0 deletions packages/vue/src/components/FPageClosablePanel/use-panel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { type Ref, ref } from "vue";

type PanelCallback<T> = (data: { item: T; reason: string }) => void;

interface ClosablePanelControl<T> {
readonly name: Readonly<Ref<string>>;
item: Ref<T | null>;
callback: Ref<PanelCallback<T> | null>;
open(item: T, options?: { onClose?: PanelCallback<T> }): void;
close(): void;
destroy(): void;
}

interface ClosablePanel<T = unknown> {
open(item: T, options?: { onClose?: PanelCallback<T> }): void;
close(): void;
}

const panels: Array<ClosablePanelControl<unknown>> = [];

export function createClosablePanel<T>(name: string): ClosablePanelControl<T> {
const control: ClosablePanelControl<unknown> = {
name: ref(name),
item: ref(null),
callback: ref(null),
open(item, options) {
this.item.value = item;
this.callback.value = options?.onClose ?? null;
},
close() {
this.item.value = null;
this.callback.value = null;
},
destroy() {
/* do nothing */
},
};
panels.push(control);
return control as ClosablePanelControl<T>;
}

export function usePanel<T = unknown>(name: string): ClosablePanel<T> {
return {
open(item, options) {
const panel = panels.find((it) => it.name.value === name);
if (panel) {
panel.open(item, options);
}
},
close() {
const panel = panels.find((it) => it.name.value === name);
if (panel) {
panel.close();
}
},
};
}
Loading
Loading