@geoffcox/sterling-svelte 1.0.6 → 1.0.9

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.
@@ -1,9 +1,9 @@
1
- <script>import { onMount } from 'svelte';
1
+ <script>import { getContext, onMount, tick } from 'svelte';
2
2
  import { arrow, autoUpdate, computePosition, flip, offset } from '@floating-ui/dom';
3
3
  import { portal } from './actions/portal';
4
- import { STERLING_PORTAL_HOST_ID } from './Popover.constants';
5
4
  import { fade } from 'svelte/transition';
6
5
  import { prefersReducedMotion } from './mediaQueries/prefersReducedMotion';
6
+ import { STERLING_PORTAL_HOST_ID, STERLING_PORTAL_CONTEXT_ID } from './Portal.constants';
7
7
  // ----- Props ----- //
8
8
  /** Conditionally renders content based on open. */
9
9
  export let conditionalRender = true;
@@ -28,23 +28,27 @@ let popupPosition = { x: 0, y: 0 };
28
28
  $: floatingUIPlacement = placement;
29
29
  let bodyHeight = 0;
30
30
  let resizeObserver = undefined;
31
+ const { portalHost: contextPortalHost } = getContext(STERLING_PORTAL_CONTEXT_ID) || {
32
+ portalHost: undefined
33
+ };
31
34
  // ----- Portal Host ----- //
32
- const ensurePortalHost = () => {
33
- if (globalThis?.document) {
34
- if (portalHost) {
35
- return portalHost;
36
- }
37
- let host = document.querySelector(`#${STERLING_PORTAL_HOST_ID}`);
35
+ const ensurePortalHost = async () => {
36
+ await tick();
37
+ // use the host set from context, usually set from a Dialog
38
+ let host = $contextPortalHost;
39
+ // use or create the sterling portal host
40
+ if (!host && globalThis?.document) {
41
+ host = globalThis.document.querySelector(`#${STERLING_PORTAL_HOST_ID}`);
42
+ // fallback to creating the sterling portal host
38
43
  if (!host) {
39
- host = document.createElement('div');
44
+ host = globalThis.document.createElement('div');
40
45
  host.id = STERLING_PORTAL_HOST_ID;
41
46
  host.style.overflow = 'visible';
42
- document.body.append(host);
47
+ globalThis.document.body.append(host);
43
48
  }
44
- portalHost = host;
45
49
  }
50
+ portalHost = host;
46
51
  };
47
- // ----- Body Height Change ----- //
48
52
  // ----- Position ----- //
49
53
  $: middleware = [
50
54
  offset({ mainAxis: mainAxisOffset, crossAxis: crossAxisOffset }),
@@ -142,7 +146,7 @@ ensurePortalHost();
142
146
 
143
147
  {#if open || !conditionalRender}
144
148
  <div
145
- use:portal={{ target: portalHost ?? globalThis?.document?.body }}
149
+ use:portal={{ target: portalHost }}
146
150
  class="sterling-callout-portal"
147
151
  transition:fadeMotion|global={{ duration: 250 }}
148
152
  >
@@ -1,5 +1,7 @@
1
- <script>import { onMount, tick } from 'svelte';
1
+ <script>import { onMount, setContext, tick } from 'svelte';
2
2
  import Button from './Button.svelte';
3
+ import { STERLING_PORTAL_CONTEXT_ID } from './Portal.constants';
4
+ import { writable } from 'svelte/store';
3
5
  const dialogFadeDuration = 250;
4
6
  // ----- Props ----- //
5
7
  /** When true, clicking outside the dialog causes the dialog close. */
@@ -19,6 +21,9 @@ let dialogRef;
19
21
  let contentRef;
20
22
  let formRef;
21
23
  let closing = false;
24
+ const portalHostStore = writable(undefined);
25
+ // ----- Context ----- //
26
+ setContext(STERLING_PORTAL_CONTEXT_ID, { portalHost: portalHostStore });
22
27
  // ----- Event Handlers ----- //
23
28
  const onDocumentClick = (event) => {
24
29
  // as tracking clicks outside the dialog is only active while the dialog is open
@@ -102,11 +107,14 @@ $: {
102
107
  }
103
108
  onMount(() => {
104
109
  updateDialog(open);
110
+ // Use the dialog for any element portals
111
+ portalHostStore.set(dialogRef);
105
112
  dialogRef.addEventListener('cancel', onCancel);
106
113
  dialogRef.addEventListener('close', onClose);
107
114
  return () => {
108
115
  dialogRef?.removeEventListener('cancel', onCancel);
109
116
  dialogRef?.removeEventListener('close', onClose);
117
+ portalHostStore.set(undefined);
110
118
  };
111
119
  });
112
120
  </script>
@@ -1,2 +1 @@
1
1
  export declare const POPOVER_PLACEMENTS: string[];
2
- export declare const STERLING_PORTAL_HOST_ID = "SterlingPortalHost";
@@ -12,4 +12,3 @@ export const POPOVER_PLACEMENTS = [
12
12
  'left',
13
13
  'left-start'
14
14
  ];
15
- export const STERLING_PORTAL_HOST_ID = 'SterlingPortalHost';
@@ -1,7 +1,7 @@
1
- <script>import { onMount } from 'svelte';
1
+ <script>import { getContext, onMount, tick } from 'svelte';
2
2
  import { autoUpdate, computePosition, flip, offset } from '@floating-ui/dom';
3
3
  import { portal } from './actions/portal';
4
- import { STERLING_PORTAL_HOST_ID } from './Popover.constants';
4
+ import { STERLING_PORTAL_HOST_ID, STERLING_PORTAL_CONTEXT_ID } from './Portal.constants';
5
5
  // ----- Props ----- //
6
6
  /** When true, content is rendered only when the popover is open. */
7
7
  export let conditionalRender = true;
@@ -25,22 +25,32 @@ let popupPosition = { x: 0, y: 0 };
25
25
  $: floatingUIPlacement = placement;
26
26
  let bodyHeight = 0;
27
27
  let resizeObserver = undefined;
28
+ const { portalHost: contextPortalHost } = getContext(STERLING_PORTAL_CONTEXT_ID) || {
29
+ portalHost: undefined
30
+ };
28
31
  // ----- Portal Host ----- //
29
- const ensurePortalHost = () => {
30
- if (globalThis?.document) {
31
- if (portalHost) {
32
- return portalHost;
33
- }
34
- let host = document.querySelector(`#${STERLING_PORTAL_HOST_ID}`);
32
+ const ensurePortalHost = async () => {
33
+ await tick();
34
+ // use the host set from context, usually set from a Dialog
35
+ let host = $contextPortalHost;
36
+ // use or create the sterling portal host
37
+ if (!host && globalThis?.document) {
38
+ host = globalThis.document.querySelector(`#${STERLING_PORTAL_HOST_ID}`);
39
+ // fallback to creating the sterling portal host
35
40
  if (!host) {
36
- host = document.createElement('div');
41
+ host = globalThis.document.createElement('div');
37
42
  host.id = STERLING_PORTAL_HOST_ID;
38
43
  host.style.overflow = 'visible';
39
- document.body.append(host);
44
+ globalThis.document.body.append(host);
40
45
  }
41
- portalHost = host;
42
46
  }
47
+ portalHost = host;
43
48
  };
49
+ $: {
50
+ if ($contextPortalHost || !$contextPortalHost) {
51
+ ensurePortalHost();
52
+ }
53
+ }
44
54
  // ----- Position ----- //
45
55
  $: middleware = [offset({ mainAxis: mainAxisOffset, crossAxis: crossAxisOffset }), flip()];
46
56
  const computePopoverPosition = async () => {
@@ -87,10 +97,7 @@ ensurePortalHost();
87
97
  </script>
88
98
 
89
99
  {#if open || !conditionalRender}
90
- <div
91
- use:portal={{ target: portalHost ?? globalThis?.document?.body }}
92
- class="sterling-popover-portal"
93
- >
100
+ <div use:portal={{ target: portalHost }} class="sterling-popover-portal">
94
101
  <!-- svelte-ignore a11y-no-static-element-interactions -->
95
102
  <div
96
103
  bind:this={popupRef}
@@ -0,0 +1,2 @@
1
+ export declare const STERLING_PORTAL_HOST_ID = "SterlingPortalHost";
2
+ export declare const STERLING_PORTAL_CONTEXT_ID = "SterlingPortalContext";
@@ -0,0 +1,2 @@
1
+ export const STERLING_PORTAL_HOST_ID = 'SterlingPortalHost';
2
+ export const STERLING_PORTAL_CONTEXT_ID = 'SterlingPortalContext';
@@ -0,0 +1,6 @@
1
+ /// <reference types="svelte" />
2
+ import type { Readable } from 'svelte/store';
3
+ export type PortalContext = {
4
+ /** The portal host for usePortal */
5
+ portalHost: Readable<HTMLElement | undefined>;
6
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,8 +1,8 @@
1
1
  export declare const portal: (node: HTMLElement, params: {
2
- target: HTMLElement;
2
+ target?: HTMLElement;
3
3
  }) => {
4
4
  update: (params: {
5
- target: HTMLElement;
5
+ target?: HTMLElement;
6
6
  }) => void;
7
7
  destroy(): void;
8
8
  };
@@ -15,7 +15,7 @@
15
15
  display: none;
16
16
  grid-template-columns: 1fr;
17
17
  grid-template-rows: 1fr;
18
- height: fit-content;
18
+ height: auto;
19
19
  left: 0;
20
20
  overflow: visible;
21
21
  position: absolute;
@@ -2,6 +2,7 @@
2
2
  padding: 0;
3
3
  border: none;
4
4
  background: none;
5
+ overflow: visible;
5
6
  }
6
7
 
7
8
  .sterling-dialog::backdrop {
@@ -9,7 +9,7 @@
9
9
  display: grid;
10
10
  grid-template-columns: 1fr;
11
11
  grid-template-rows: 1fr;
12
- height: fit-content;
12
+ height: auto;
13
13
  padding: 0.25em;
14
14
  }
15
15
 
@@ -8,7 +8,7 @@
8
8
  display: none;
9
9
  grid-template-columns: 1fr;
10
10
  grid-template-rows: 1fr;
11
- height: fit-content;
11
+ height: auto;
12
12
  left: 0;
13
13
  overflow: visible;
14
14
  position: absolute;
@@ -1,3 +1,2 @@
1
1
  @import url('./Radio.base.css');
2
2
  @import url('./Radio.colorful.css');
3
- @import url('./Radio.button.css');
package/dist/index.d.ts CHANGED
@@ -65,3 +65,4 @@ import TreeChevron from './TreeChevron.svelte';
65
65
  import TreeItem from './TreeItem.svelte';
66
66
  import TreeItemDisplay from './TreeItemDisplay.svelte';
67
67
  export { Button, Callout, Checkbox, ColorPicker, Dialog, Dropdown, HexColorSliders, HslColorSliders, Input, Label, Link, List, ListItem, Menu, MenuBar, MenuButton, MenuItem, MenuItemDisplay, MenuSeparator, Popover, Progress, Radio, RgbColorSliders, Select, Slider, Switch, Tab, TabList, TextArea, Tooltip, Tree, TreeChevron, TreeItem, TreeItemDisplay };
68
+ export * from './css/sterling.css';
package/dist/index.js CHANGED
@@ -58,3 +58,4 @@ import TreeChevron from './TreeChevron.svelte';
58
58
  import TreeItem from './TreeItem.svelte';
59
59
  import TreeItemDisplay from './TreeItemDisplay.svelte';
60
60
  export { Button, Callout, Checkbox, ColorPicker, Dialog, Dropdown, HexColorSliders, HslColorSliders, Input, Label, Link, List, ListItem, Menu, MenuBar, MenuButton, MenuItem, MenuItemDisplay, MenuSeparator, Popover, Progress, Radio, RgbColorSliders, Select, Slider, Switch, Tab, TabList, TextArea, Tooltip, Tree, TreeChevron, TreeItem, TreeItemDisplay };
61
+ export * from './css/sterling.css';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geoffcox/sterling-svelte",
3
- "version": "1.0.6",
3
+ "version": "1.0.9",
4
4
  "author": "Geoff Cox",
5
5
  "description": "A modern, accessible, and lightweight component library for Svelte.",
6
6
  "license": "MIT",
@@ -44,10 +44,11 @@
44
44
  ".": {
45
45
  "types": "./dist/index.d.ts",
46
46
  "svelte": "./dist/index.js"
47
- }
47
+ },
48
+ "./css/*.css": "./dist/css/*.css"
48
49
  },
49
50
  "files": [
50
- "dist",
51
+ "dist/*",
51
52
  "!dist/**/*.test.*",
52
53
  "!dist/**/*.spec.*"
53
54
  ],
@@ -71,14 +72,15 @@
71
72
  "@fontsource/open-sans": "^4.5.14",
72
73
  "@fontsource/source-code-pro": "^4.5.14",
73
74
  "@playwright/test": "^1.28.1",
75
+ "@stackblitz/sdk": "^1.10.0",
74
76
  "@sveltejs/adapter-auto": "^3.0.0",
75
77
  "@sveltejs/adapter-static": "^3.0.0",
76
78
  "@sveltejs/kit": "^2.0.0",
77
79
  "@sveltejs/package": "^2.0.0",
78
- "@types/lodash-es": "^4.17.6",
79
- "@types/tinycolor2": "^1.4.3",
80
80
  "@sveltejs/vite-plugin-svelte": "^3.0.0",
81
81
  "@types/eslint": "^8.56.7",
82
+ "@types/lodash-es": "^4.17.6",
83
+ "@types/tinycolor2": "^1.4.3",
82
84
  "eslint": "^9.0.0",
83
85
  "eslint-config-prettier": "^9.1.0",
84
86
  "eslint-plugin-svelte": "^2.36.0",
@@ -1,21 +0,0 @@
1
- .sterling-popover-portal {
2
- position: relative;
3
- overflow: visible;
4
- }
5
-
6
- .sterling-popover {
7
- box-sizing: border-box;
8
- display: none;
9
- grid-template-columns: 1fr;
10
- grid-template-rows: 1fr;
11
- height: fit-content;
12
- left: 0;
13
- overflow: visible;
14
- position: absolute;
15
- top: 0;
16
- width: max-content;
17
- }
18
-
19
- .sterling-popover.open {
20
- display: grid;
21
- }
@@ -1,113 +0,0 @@
1
- .sterling-radio.button {
2
- align-content: center;
3
- align-items: center;
4
- background-color: var(--stsv-button__background-color);
5
- border-color: var(--stsv-button__border-color);
6
- border-radius: 0;
7
- border-style: solid;
8
- border-width: 2px;
9
- box-sizing: border-box;
10
- color: var(--stsv-button__color);
11
- cursor: pointer;
12
- display: inline-flex;
13
- flex-direction: row;
14
- font: inherit;
15
- justify-content: center;
16
- justify-items: center;
17
- margin-left: -2px;
18
- overflow: hidden;
19
- padding: 0.5em 1em;
20
- position: relative;
21
- text-decoration: none;
22
- text-overflow: ellipsis;
23
- transition: background-color 250ms, color 250ms, border-color 250ms;
24
- white-space: nowrap;
25
- user-select: none;
26
- }
27
-
28
- /* .sterling-radio.button:first-child {
29
- border-top-left-radius: 8px;
30
- border-bottom-left-radius: 8px;
31
- border-left-width: 2px;
32
- }
33
-
34
- .sterling-radio.button:last-child {
35
- border-top-right-radius: 8px;
36
- border-bottom-right-radius: 8px;
37
- } */
38
-
39
- .sterling-radio.button:not(.checked):not(.disabled):hover {
40
- background-color: var(--stsv-button__background-color--hover);
41
- border-color: var(--stsv-button__border-color--hover);
42
- color: var(--stsv-button__color--hover);
43
- }
44
-
45
- .sterling-radio.button.checked {
46
- background-color: var(--stsv-button__background-color--active);
47
- border-color: var(--stsv-button__border-color--active);
48
- color: var(--stsv-button__color--active);
49
- }
50
-
51
- .sterling-radio.button.using-keyboard:focus-within {
52
- border-color: var(--stsv-button__border-color--focus);
53
- outline-color: var(--stsv-common__outline-color);
54
- outline-offset: 0;
55
- outline-style: solid;
56
- outline-width: 2px;
57
- z-index: 1;
58
- }
59
-
60
- .sterling-radio.button .container {
61
- margin-right: 0;
62
- }
63
-
64
- .sterling-radio.button input {
65
- height: 0;
66
- width: 0;
67
- }
68
-
69
- .sterling-radio.button.disabled * {
70
- cursor: not-allowed;
71
- }
72
-
73
- .sterling-radio.button.disabled::after {
74
- content: '';
75
- position: absolute;
76
- left: 0;
77
- right: 0;
78
- top: 0;
79
- bottom: 0;
80
- background: repeating-linear-gradient(
81
- var(--stsv-common--disabled__stripe-angle),
82
- var(--stsv-common--disabled__stripe-color),
83
- var(--stsv-common--disabled__stripe-color) var(--stsv-common--disabled__stripe-width),
84
- var(--stsv-common--disabled__stripe-color--alt) var(--stsv-common--disabled__stripe-width),
85
- var(--stsv-common--disabled__stripe-color--alt)
86
- calc(2 * var(--stsv-common--disabled__stripe-width))
87
- );
88
- pointer-events: none;
89
- }
90
-
91
- .sterling-radio.button .indicator,
92
- .sterling-radio.button input:checked + .indicator,
93
- .sterling-radio.button:not(.disabled):hover .indicator,
94
- .sterling-radio.button input:focus-visible + .indicator {
95
- display: none;
96
- }
97
-
98
- .sterling-radio.button .indicator::after,
99
- .sterling-radio.button input:checked + .indicator::after {
100
- display: none;
101
- }
102
- .sterling-radio.button .container::after,
103
- .sterling-radio.button.disabled .container::after {
104
- display: none;
105
- opacity: 0;
106
- }
107
-
108
- @media (prefers-reduced-motion) {
109
- .sterling-radio.button,
110
- .sterling-radio.button::after {
111
- transition: none;
112
- }
113
- }