mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-14 18:01:06 +00:00
feat(portal): support portal
This commit is contained in:
parent
0ea3d9351e
commit
1ddd9ba1a5
14 changed files with 240 additions and 2 deletions
|
@ -1,6 +1,6 @@
|
|||
# Component Index
|
||||
|
||||
> 165 components exported from carbon-components-svelte@0.89.2.
|
||||
> 167 components exported from carbon-components-svelte@0.89.2.
|
||||
|
||||
## Components
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
|||
- [`FileUploaderItem`](#fileuploaderitem)
|
||||
- [`FileUploaderSkeleton`](#fileuploaderskeleton)
|
||||
- [`Filename`](#filename)
|
||||
- [`FloatingPortal`](#floatingportal)
|
||||
- [`FluidForm`](#fluidform)
|
||||
- [`Form`](#form)
|
||||
- [`FormGroup`](#formgroup)
|
||||
|
@ -95,6 +96,7 @@
|
|||
- [`PaginationSkeleton`](#paginationskeleton)
|
||||
- [`PasswordInput`](#passwordinput)
|
||||
- [`Popover`](#popover)
|
||||
- [`Portal`](#portal)
|
||||
- [`ProgressBar`](#progressbar)
|
||||
- [`ProgressIndicator`](#progressindicator)
|
||||
- [`ProgressIndicatorSkeleton`](#progressindicatorskeleton)
|
||||
|
@ -1435,6 +1437,20 @@ None.
|
|||
| click | forwarded | -- |
|
||||
| keydown | forwarded | -- |
|
||||
|
||||
## `FloatingPortal`
|
||||
|
||||
### Props
|
||||
|
||||
None.
|
||||
|
||||
### Slots
|
||||
|
||||
None.
|
||||
|
||||
### Events
|
||||
|
||||
None.
|
||||
|
||||
## `FluidForm`
|
||||
|
||||
### Props
|
||||
|
@ -2835,6 +2851,22 @@ None.
|
|||
| :------------ | :--------- | :------------------------------------ |
|
||||
| click:outside | dispatched | <code>{ target: HTMLElement; }</code> |
|
||||
|
||||
## `Portal`
|
||||
|
||||
### Props
|
||||
|
||||
None.
|
||||
|
||||
### Slots
|
||||
|
||||
| Slot name | Default | Props | Fallback |
|
||||
| :-------- | :------ | :---- | :------- |
|
||||
| -- | Yes | -- | -- |
|
||||
|
||||
### Events
|
||||
|
||||
None.
|
||||
|
||||
## `ProgressBar`
|
||||
|
||||
### Props
|
||||
|
|
1
docs/package-lock.json
generated
1
docs/package-lock.json
generated
|
@ -30,6 +30,7 @@
|
|||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@ibm/telemetry-js": "^1.5.0",
|
||||
"flatpickr": "4.6.9"
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"total": 165,
|
||||
"total": 167,
|
||||
"components": [
|
||||
{
|
||||
"moduleName": "Accordion",
|
||||
|
@ -5241,6 +5241,16 @@
|
|||
"name": "div | button | svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"moduleName": "FloatingPortal",
|
||||
"filePath": "src/Portal/FloatingPortal.svelte",
|
||||
"props": [],
|
||||
"moduleExports": [],
|
||||
"slots": [],
|
||||
"events": [],
|
||||
"typedefs": [],
|
||||
"generics": null
|
||||
},
|
||||
{
|
||||
"moduleName": "FluidForm",
|
||||
"filePath": "src/FluidForm/FluidForm.svelte",
|
||||
|
@ -10851,6 +10861,22 @@
|
|||
"name": "div"
|
||||
}
|
||||
},
|
||||
{
|
||||
"moduleName": "Portal",
|
||||
"filePath": "src/Portal/Portal.svelte",
|
||||
"props": [],
|
||||
"moduleExports": [],
|
||||
"slots": [
|
||||
{
|
||||
"name": "__default__",
|
||||
"default": true,
|
||||
"slot_props": "{}"
|
||||
}
|
||||
],
|
||||
"events": [],
|
||||
"typedefs": [],
|
||||
"generics": null
|
||||
},
|
||||
{
|
||||
"moduleName": "ProgressBar",
|
||||
"filePath": "src/ProgressBar/ProgressBar.svelte",
|
||||
|
|
8
docs/src/pages/components/Portal.svx
Normal file
8
docs/src/pages/components/Portal.svx
Normal file
|
@ -0,0 +1,8 @@
|
|||
<script>
|
||||
import { Portal } from "carbon-components-svelte";
|
||||
import Preview from "../../components/Preview.svelte";
|
||||
</script>
|
||||
|
||||
## Default
|
||||
|
||||
<FileSource src="/framed/Portal/BasicPortal" />
|
6
docs/src/pages/framed/Portal/BasicPortal.svelte
Normal file
6
docs/src/pages/framed/Portal/BasicPortal.svelte
Normal file
|
@ -0,0 +1,6 @@
|
|||
<script>
|
||||
import { Portal } from "carbon-components-svelte";
|
||||
</script>
|
||||
|
||||
<Portal>Hello world</Portal>
|
||||
<Portal>Another portal</Portal>
|
26
package-lock.json
generated
26
package-lock.json
generated
|
@ -10,6 +10,7 @@
|
|||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@ibm/telemetry-js": "^1.5.0",
|
||||
"flatpickr": "4.6.9"
|
||||
},
|
||||
|
@ -623,6 +624,31 @@
|
|||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/core": {
|
||||
"version": "1.6.9",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz",
|
||||
"integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/utils": "^0.2.9"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/dom": {
|
||||
"version": "1.6.13",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz",
|
||||
"integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/core": "^1.6.0",
|
||||
"@floating-ui/utils": "^0.2.9"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/utils": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz",
|
||||
"integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@hutson/parse-repository-url": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz",
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
"release": "standard-version && npm run build:docs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.6.13",
|
||||
"@ibm/telemetry-js": "^1.5.0",
|
||||
"flatpickr": "4.6.9"
|
||||
},
|
||||
|
|
62
src/Portal/FloatingPortal.svelte
Normal file
62
src/Portal/FloatingPortal.svelte
Normal file
|
@ -0,0 +1,62 @@
|
|||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import { computePosition, autoUpdate } from "@floating-ui/dom";
|
||||
import Portal from "./Portal.svelte";
|
||||
|
||||
/** @type {null | HTMLButtonElement} */
|
||||
let button = null;
|
||||
|
||||
/** @type {null | HTMLDivElement} */
|
||||
let tooltip = null;
|
||||
|
||||
let togglePortal = false;
|
||||
let padding = 10;
|
||||
|
||||
/** @type {null | ReturnType<typeof autoUpdate>} */
|
||||
let cleanup = null;
|
||||
|
||||
function updatePosition() {
|
||||
if (!button || !tooltip) return;
|
||||
computePosition(button, tooltip).then(({ x, y }) => {
|
||||
if (!tooltip) return;
|
||||
Object.assign(tooltip.style, {
|
||||
left: `${x}px`,
|
||||
top: `${y}px`,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
updatePosition();
|
||||
|
||||
if (button && tooltip) {
|
||||
cleanup = autoUpdate(button, tooltip, updatePosition);
|
||||
}
|
||||
|
||||
return () => {
|
||||
return cleanup?.();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
style="padding: {padding}px"
|
||||
bind:this={button}
|
||||
on:click={() => (padding += 2)}
|
||||
>
|
||||
Click to increase padding
|
||||
</button>
|
||||
|
||||
<button
|
||||
on:click={() => {
|
||||
togglePortal = !togglePortal;
|
||||
}}
|
||||
>
|
||||
Toggle portal
|
||||
</button>
|
||||
{#if togglePortal}
|
||||
<Portal>
|
||||
<div bind:this={tooltip}>Floating menu</div>
|
||||
</Portal>
|
||||
{/if}
|
53
src/Portal/Portal.svelte
Normal file
53
src/Portal/Portal.svelte
Normal file
|
@ -0,0 +1,53 @@
|
|||
<script context="module">
|
||||
/** @type {HTMLDivElement | null} */
|
||||
let portalContainer = null;
|
||||
|
||||
let instances = 0;
|
||||
|
||||
/**
|
||||
* Creates or returns the shared portal container
|
||||
* @returns {HTMLDivElement}
|
||||
*/
|
||||
function getPortalContainer() {
|
||||
if (!portalContainer && typeof document !== "undefined") {
|
||||
portalContainer = document.createElement("div");
|
||||
portalContainer.setAttribute("data-portal", "");
|
||||
document.body.appendChild(portalContainer);
|
||||
}
|
||||
|
||||
return portalContainer;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { onMount } from "svelte";
|
||||
|
||||
/** @type {null | HTMLDivElement} */
|
||||
let portal = null;
|
||||
|
||||
onMount(() => {
|
||||
instances++;
|
||||
const container = getPortalContainer();
|
||||
|
||||
if (portal && container) {
|
||||
container.appendChild(portal);
|
||||
}
|
||||
|
||||
return () => {
|
||||
instances--;
|
||||
|
||||
if (portal?.parentNode) {
|
||||
portal.parentNode.removeChild(portal);
|
||||
}
|
||||
|
||||
if (instances === 0 && portalContainer?.parentNode) {
|
||||
portalContainer.parentNode.removeChild(portalContainer);
|
||||
portalContainer = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<div bind:this={portal}>
|
||||
<slot />
|
||||
</div>
|
2
src/Portal/index.js
Normal file
2
src/Portal/index.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
export { default as Portal } from "./Portal.svelte";
|
||||
export { default as FloatingPortal } from "./FloatingPortal.svelte";
|
|
@ -91,6 +91,7 @@ export {
|
|||
ProgressIndicatorSkeleton,
|
||||
ProgressStep,
|
||||
} from "./ProgressIndicator";
|
||||
export { Portal, FloatingPortal } from "./Portal";
|
||||
export { RadioButton, RadioButtonSkeleton } from "./RadioButton";
|
||||
export { RadioButtonGroup } from "./RadioButtonGroup";
|
||||
export { RecursiveList } from "./RecursiveList";
|
||||
|
|
9
types/Portal/FloatingPortal.svelte.d.ts
vendored
Normal file
9
types/Portal/FloatingPortal.svelte.d.ts
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
import type { SvelteComponentTyped } from "svelte";
|
||||
|
||||
export type FloatingPortalProps = {};
|
||||
|
||||
export default class FloatingPortal extends SvelteComponentTyped<
|
||||
FloatingPortalProps,
|
||||
Record<string, any>,
|
||||
{}
|
||||
> {}
|
9
types/Portal/Portal.svelte.d.ts
vendored
Normal file
9
types/Portal/Portal.svelte.d.ts
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
import type { SvelteComponentTyped } from "svelte";
|
||||
|
||||
export type PortalProps = {};
|
||||
|
||||
export default class Portal extends SvelteComponentTyped<
|
||||
PortalProps,
|
||||
Record<string, any>,
|
||||
{ default: {} }
|
||||
> {}
|
2
types/index.d.ts
vendored
2
types/index.d.ts
vendored
|
@ -95,6 +95,8 @@ export { default as ProgressBar } from "./ProgressBar/ProgressBar.svelte";
|
|||
export { default as ProgressIndicator } from "./ProgressIndicator/ProgressIndicator.svelte";
|
||||
export { default as ProgressIndicatorSkeleton } from "./ProgressIndicator/ProgressIndicatorSkeleton.svelte";
|
||||
export { default as ProgressStep } from "./ProgressIndicator/ProgressStep.svelte";
|
||||
export { default as Portal } from "./Portal/Portal.svelte";
|
||||
export { default as FloatingPortal } from "./Portal/FloatingPortal.svelte";
|
||||
export { default as RadioButton } from "./RadioButton/RadioButton.svelte";
|
||||
export { default as RadioButtonSkeleton } from "./RadioButton/RadioButtonSkeleton.svelte";
|
||||
export { default as RadioButtonGroup } from "./RadioButtonGroup/RadioButtonGroup.svelte";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue