@abcnews/components-builder 0.0.12 → 0.0.14

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/README.md CHANGED
@@ -136,6 +136,11 @@ You can provide your own footer elements to make either an okay/cancel alert, or
136
136
 
137
137
  This uses the native dialogue element, so focus will always be inside the modal. Take care not to show more than one at a time.
138
138
 
139
+ Use the `position` prop to control where the modal appears:
140
+
141
+ - `centre` (default): Centred in the screen with a full dark backdrop.
142
+ - `right`: Aligned to the right, with a gradient backdrop that leaves your viz visible. Especially useful when the modal changes the viz reactively, so you can see the results.
143
+
139
144
  ```svelte
140
145
  {#snippet children()}
141
146
  Hello this is the modal content
@@ -144,7 +149,7 @@ This uses the native dialogue element, so focus will always be inside the modal.
144
149
  <button onclick={() => (isOpen = false)}>Ok!</button>
145
150
  {/snippet}
146
151
 
147
- <Modal title="Example modal" {children} {footerChildren} />
152
+ <Modal title="Example modal" {children} {footerChildren} position="right" />
148
153
  ```
149
154
 
150
155
  ## Google Doc Scrollyteller
@@ -53,51 +53,58 @@
53
53
  border: 1px solid rgba(0, 0, 0, 0.2);
54
54
  border-radius: 0.5rem;
55
55
  animation: fadein 0.2s;
56
- &::backdrop {
57
- animation: fadein 0.2s;
58
- background: rgba(0, 0, 0, 0.05);
59
- }
60
- :global {
61
- .menu {
62
- list-style: none;
63
- margin: 0;
64
- padding: 0;
65
- }
66
- .menu--double {
67
- display: grid;
68
- grid-template-columns: 50% 50%;
69
- gap: 0.25rem;
70
- & li {
71
- white-space: nowrap;
72
- }
73
- }
74
- .section {
75
- padding: 0.75rem;
76
- }
56
+ }
77
57
 
78
- .item,
79
- button.item {
80
- display: block;
81
- width: 100%;
82
- border: none;
83
- background: none;
84
- text-align: left;
85
- cursor: pointer;
86
- margin: 0 !important;
87
- font-size: 1rem;
88
- &:focus-visible,
89
- &:hover {
90
- background: Highlight;
91
- color: HighlightText;
92
- }
93
- }
94
- hr {
95
- border: none;
96
- margin: 0;
97
- padding: 0;
98
- border-bottom: 1px solid var(--border);
99
- }
100
- }
58
+ .dialog::backdrop {
59
+ animation: fadein 0.2s;
60
+ background: rgba(0, 0, 0, 0.05);
61
+ }
62
+
63
+ :global(.dialog .menu) {
64
+ list-style: none;
65
+ margin: 0;
66
+ padding: 0;
67
+ }
68
+
69
+ :global(.dialog .menu--double) {
70
+ display: grid;
71
+ grid-template-columns: 50% 50%;
72
+ gap: 0.25rem;
73
+ }
74
+
75
+ :global(.dialog .menu--double li) {
76
+ white-space: nowrap;
77
+ }
78
+
79
+ :global(.dialog .section) {
80
+ padding: 0.75rem;
81
+ }
82
+
83
+ :global(.dialog .item),
84
+ :global(.dialog button.item) {
85
+ display: block;
86
+ width: 100%;
87
+ border: none;
88
+ background: none;
89
+ text-align: left;
90
+ cursor: pointer;
91
+ margin: 0 !important;
92
+ font-size: 1rem;
93
+ }
94
+
95
+ :global(.dialog .item:focus-visible),
96
+ :global(.dialog .item:hover),
97
+ :global(.dialog button.item:focus-visible),
98
+ :global(.dialog button.item:hover) {
99
+ background: Highlight;
100
+ color: HighlightText;
101
+ }
102
+
103
+ :global(.dialog hr) {
104
+ border: none;
105
+ margin: 0;
106
+ padding: 0;
107
+ border-bottom: 1px solid var(--border);
101
108
  }
102
109
 
103
110
  @keyframes fadein {
@@ -24,7 +24,7 @@
24
24
 
25
25
  let hasLoaded = $state(false);
26
26
  let markers = $state<Marker[]>([]);
27
- let mode = $state(Object.keys(prefixes)?.[0]);
27
+ let mode = $state(untrack(() => Object.keys(prefixes)?.[0]));
28
28
 
29
29
  /** which button should show the success indicator */
30
30
  let successIndicator = $state("");
@@ -33,7 +33,9 @@
33
33
  window.location.pathname
34
34
  .match(/\/news-projects\/[^/]+\/(\d+\.\d+\.\d+)/)
35
35
  ?.slice(1) || [];
36
- const localStorageKey = `ABC_NEWS_BUILDER_${projectName.toUpperCase().replace(/-/g, "_")}`;
36
+ const localStorageKey = $derived(
37
+ `ABC_NEWS_BUILDER_${projectName.toUpperCase().replace(/-/g, "_")}`,
38
+ );
37
39
 
38
40
  /** Load & sanitise markers from localStorage on initial load */
39
41
  $effect(() => {
@@ -76,7 +78,7 @@
76
78
  }
77
79
 
78
80
  interval = setInterval(() => {
79
- const goodMarkers = (marker) =>
81
+ const goodMarkers = (marker: Marker) =>
80
82
  !marker.deleted || marker.deleted > Date.now() - 5000;
81
83
  if (!_markers.every(goodMarkers)) {
82
84
  markers = _markers.filter(goodMarkers);
@@ -240,7 +242,7 @@
240
242
  }
241
243
 
242
244
  let sanitisedMarker = text;
243
- Object.keys(prefixes).forEach(
245
+ Object.values(prefixes).forEach(
244
246
  (prefix) => (sanitisedMarker = sanitisedMarker.replace(prefix, "")),
245
247
  );
246
248
 
@@ -1,116 +1,138 @@
1
1
  <script lang="ts">
2
- import { onMount } from 'svelte';
3
- import { X } from 'svelte-bootstrap-icons';
2
+ import { onMount } from "svelte";
3
+ import { X } from "svelte-bootstrap-icons";
4
4
 
5
- let { children, footerChildren, title = '', onClose = () => {} } = $props();
6
- let dialogEl = $state<HTMLDialogElement | undefined>();
7
- let rect = $state<DOMRect>();
8
- $effect(() => {
9
- if (dialogEl) {
10
- rect = dialogEl.getBoundingClientRect();
11
- }
12
- });
13
- onMount(() => {
14
- dialogEl?.showModal();
15
- return () => {
16
- dialogEl?.close();
17
- };
18
- });
5
+ let {
6
+ children,
7
+ footerChildren,
8
+ title = "",
9
+ onClose = () => {},
10
+ position = "centre",
11
+ } = $props<{
12
+ children?: any;
13
+ footerChildren?: any;
14
+ title?: string;
15
+ onClose?: () => void;
16
+ position?: string;
17
+ }>();
18
+ let dialogEl = $state<HTMLDialogElement | undefined>();
19
+ let rect = $state<DOMRect>();
20
+ $effect(() => {
21
+ if (dialogEl) {
22
+ rect = dialogEl.getBoundingClientRect();
23
+ }
24
+ });
25
+ onMount(() => {
26
+ dialogEl?.showModal();
27
+ return () => {
28
+ dialogEl?.close();
29
+ };
30
+ });
19
31
 
20
- /* Proxy required otherwise Typescript complains */
21
- function onCloseTypescriptProxy() {
22
- onClose();
23
- }
32
+ function onCloseTypescriptProxy(e) {
33
+ if (e.target === dialogEl) {
34
+ onClose();
35
+ }
36
+ }
24
37
  </script>
25
38
 
26
39
  <!-- svelte-ignore a11y_click_events_have_key_events -->
27
40
  <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
41
+ <!-- We must track clicks on the modal so clicking the backdrop can close it. This is not an accessibility issue. -->
28
42
  <dialog
29
- class="modal"
30
- bind:this={dialogEl}
31
- onclick={onCloseTypescriptProxy}
32
- onclose={onCloseTypescriptProxy}
43
+ bind:this={dialogEl}
44
+ class="modal modal--{position}"
45
+ onclick={onCloseTypescriptProxy}
46
+ onclose={onCloseTypescriptProxy}
33
47
  >
34
- <!-- svelte-ignore a11y_no_static_element_interactions -->
35
- <div onclick={(e) => e.stopPropagation()}>
36
- {#if title}
37
- <div class="modal-title">
38
- <h1>
39
- {title}
40
- </h1>
41
- <button class="modal-close" onclick={onCloseTypescriptProxy}>
42
- <X />
43
- </button>
44
- </div>
45
- {/if}
48
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
49
+ <div onclick={(e) => e.stopPropagation()}>
50
+ {#if title}
51
+ <div class="modal-title">
52
+ <h1>
53
+ {title}
54
+ </h1>
55
+ <button class="modal-close" onclick={onCloseTypescriptProxy}>
56
+ <X />
57
+ </button>
58
+ </div>
59
+ {/if}
46
60
 
47
- <div class="modal-content">
48
- {@render children?.()}
49
- </div>
50
- {#if footerChildren}
51
- <div class="modal-footer">
52
- {@render footerChildren?.()}
53
- </div>
54
- {/if}
55
- </div>
61
+ <div class="modal-content">
62
+ {@render children?.()}
63
+ </div>
64
+ {#if footerChildren}
65
+ <div class="modal-footer">
66
+ {@render footerChildren?.()}
67
+ </div>
68
+ {/if}
69
+ </div>
56
70
  </dialog>
57
71
 
58
72
  <style>
59
- .modal {
60
- left: 50%;
61
- top: 50%;
62
- transform: translate(-50%, -50%);
63
- margin: 0;
64
- padding: 0;
65
- background: var(--background);
66
- color: var(--text);
67
- border: 1px solid var(--border);
68
- border-radius: 0.5rem;
69
- animation: fadein 0.2s;
70
- &::backdrop {
71
- animation: fadein 0.2s;
72
- background: rgba(0, 0, 0, 0.8);
73
- }
74
- }
73
+ .modal {
74
+ left: 50%;
75
+ top: 50%;
76
+ transform: translate(-50%, -50%);
77
+ margin: 0;
78
+ padding: 0;
79
+ background: var(--background);
80
+ color: var(--text);
81
+ border: 1px solid var(--border);
82
+ border-radius: 0.5rem;
83
+ animation: fadein 0.2s;
84
+ &::backdrop {
85
+ animation: fadein 0.2s;
86
+ background: rgba(0, 0, 0, 0.8);
87
+ }
88
+ }
89
+ .modal--right {
90
+ left: 100%;
91
+ transform: translate(calc(-100% - 2rem), -50%);
92
+ &::backdrop {
93
+ animation: fadein 0.2s;
94
+ background: linear-gradient(to left, rgba(0, 0, 0, 0.8), transparent 50%);
95
+ }
96
+ }
75
97
 
76
- .modal-title {
77
- display: flex;
78
- align-items: center;
79
- justify-content: center;
80
- padding: 0.5rem 0.5rem 0.5rem 1rem;
81
- gap: 1rem;
82
- border-bottom: 1px solid var(--border);
83
- }
84
- .modal-title h1 {
85
- font-size: 1rem;
86
- margin: 0;
87
- padding: 0;
88
- flex: 1;
89
- }
90
- button.modal-close {
91
- width: 2rem;
92
- border: none;
93
- height: 2rem;
94
- display: flex;
95
- justify-content: center;
96
- align-items: center;
97
- }
98
- .modal-content {
99
- padding: 0.5rem 1rem;
100
- max-height: 50vh;
101
- overflow: auto;
102
- }
103
- .modal-footer {
104
- text-align: right;
105
- border-top: 1px solid var(--border);
106
- padding: 0.5rem 1rem;
107
- }
108
- @keyframes fadein {
109
- from {
110
- opacity: 0;
111
- }
112
- to {
113
- opacity: 1;
114
- }
115
- }
98
+ .modal-title {
99
+ display: flex;
100
+ align-items: center;
101
+ justify-content: center;
102
+ padding: 0.5rem 0.5rem 0.5rem 1rem;
103
+ gap: 1rem;
104
+ border-bottom: 1px solid var(--border);
105
+ }
106
+ .modal-title h1 {
107
+ font-size: 1rem;
108
+ margin: 0;
109
+ padding: 0;
110
+ flex: 1;
111
+ }
112
+ button.modal-close {
113
+ width: 2rem;
114
+ border: none;
115
+ height: 2rem;
116
+ display: flex;
117
+ justify-content: center;
118
+ align-items: center;
119
+ }
120
+ .modal-content {
121
+ padding: 0.5rem 1rem;
122
+ max-height: 50vh;
123
+ overflow: hidden auto;
124
+ }
125
+ .modal-footer {
126
+ text-align: right;
127
+ border-top: 1px solid var(--border);
128
+ padding: 0.5rem 1rem;
129
+ }
130
+ @keyframes fadein {
131
+ from {
132
+ opacity: 0;
133
+ }
134
+ to {
135
+ opacity: 1;
136
+ }
137
+ }
116
138
  </style>
@@ -1,8 +1,10 @@
1
- declare const Modal: import("svelte").Component<{
2
- children: any;
3
- footerChildren: any;
1
+ type $$ComponentProps = {
2
+ children?: any;
3
+ footerChildren?: any;
4
4
  title?: string;
5
- onClose?: Function;
6
- }, {}, "">;
5
+ onClose?: () => void;
6
+ position?: string;
7
+ };
8
+ declare const Modal: import("svelte").Component<$$ComponentProps, {}, "">;
7
9
  type Modal = ReturnType<typeof Modal>;
8
10
  export default Modal;
@@ -17,7 +17,7 @@
17
17
  } = $props();
18
18
 
19
19
  const uniqueId = "list" + (Math.random() * 10e15).toString(16);
20
- let selectedValues = $state<string[]>(value);
20
+ let selectedValues = $state<string[]>(untrack(() => value));
21
21
  let isFocused = $state(false);
22
22
  let inputElement = $state<HTMLInputElement>();
23
23
  let inputValue = $state("");
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import Modal from "../Modal/Modal.svelte";
3
- import { onMount } from "svelte";
3
+ import { onMount, untrack } from "svelte";
4
4
 
5
5
  type NewVersion = {
6
6
  newVersion: string;
@@ -12,9 +12,10 @@
12
12
  buttonText = "Open new builder",
13
13
  }: { overrideNewVersion?: NewVersion; buttonText?: string } = $props();
14
14
 
15
- let newVersion = $state<NewVersion | undefined>(overrideNewVersion);
16
- // svelte-ignore state_referenced_locally
17
- let isOpen = $state(!!newVersion);
15
+ let newVersion = $state<NewVersion | undefined>(
16
+ untrack(() => overrideNewVersion),
17
+ );
18
+ let isOpen = $state(untrack(() => !!newVersion));
18
19
 
19
20
  /**
20
21
  * Check for a new version of the given project
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abcnews/components-builder",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build && npm run prepack",