@txstate-mws/svelte-components 1.0.1 → 1.1.0

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.
Files changed (162) hide show
  1. package/.eslintrc.cjs +37 -0
  2. package/README.md +33 -14
  3. package/docs/stores.md +1 -1
  4. package/package.json +24 -74
  5. package/playwright.config.js +112 -0
  6. package/src/app.html +14 -0
  7. package/src/global.d.ts +1 -0
  8. package/src/lib/actions/buttonify.ts +27 -0
  9. package/src/lib/actions/glue.ts +96 -0
  10. package/src/lib/actions/index.ts +7 -0
  11. package/src/lib/actions/offset.ts +43 -0
  12. package/src/lib/actions/portal.ts +13 -0
  13. package/src/lib/actions/resize.ts +72 -0
  14. package/src/lib/actions/sticky.ts +105 -0
  15. package/src/lib/actions/stickyfixed.ts +160 -0
  16. package/src/lib/components/Card.svelte +25 -0
  17. package/src/lib/components/CardLayout.svelte +188 -0
  18. package/{dist/ts → src/lib}/components/CollapsingTable.svelte +6 -5
  19. package/{dist/ts → src/lib}/components/ConditionalWrapper.svelte +0 -0
  20. package/{dist/ts → src/lib}/components/FocusLock.svelte +7 -6
  21. package/{dist/ts → src/lib}/components/Modal.svelte +5 -4
  22. package/src/lib/components/MultiSelect.svelte +174 -0
  23. package/{dist/ts → src/lib}/components/PopupMenu.svelte +22 -16
  24. package/{dist/ts → src/lib}/components/ScreenReaderOnly.svelte +2 -2
  25. package/src/lib/components/index.ts +9 -0
  26. package/src/lib/index.ts +4 -0
  27. package/src/lib/types/CardLayout.ts +14 -0
  28. package/src/lib/types/CollapsingTable.ts +8 -0
  29. package/src/lib/types/PopupMenu.ts +5 -0
  30. package/src/lib/types/index.ts +3 -0
  31. package/src/lib/util/bodyoffset.ts +77 -0
  32. package/src/lib/util/index.ts +3 -0
  33. package/src/lib/util/repositioned.ts +91 -0
  34. package/src/lib/util/util.ts +36 -0
  35. package/src/routes/__layout.svelte +125 -0
  36. package/src/routes/actions/index.svelte +1 -0
  37. package/src/routes/actions/offset.svelte +4 -0
  38. package/src/routes/actions/offsetdebounce.svelte +4 -0
  39. package/src/routes/actions/resize.svelte +4 -0
  40. package/src/routes/actions/resizedebounce.svelte +4 -0
  41. package/src/routes/actions/sticky.svelte +4 -0
  42. package/src/routes/cards/index.svelte +4 -0
  43. package/src/routes/cards/preserve.svelte +4 -0
  44. package/src/routes/collapsingtable/index.svelte +4 -0
  45. package/src/routes/collapsingtable/stickyheader.svelte +4 -0
  46. package/src/routes/index.svelte +2 -0
  47. package/src/routes/modal.svelte +4 -0
  48. package/src/routes/multiselect.svelte +4 -0
  49. package/src/routes/popupmenu/body.svelte +4 -0
  50. package/src/routes/popupmenu/complex.svelte +4 -0
  51. package/src/routes/popupmenu/empty.svelte +5 -0
  52. package/src/routes/popupmenu/index.svelte +4 -0
  53. package/src/routes/popupmenu/parent.svelte +4 -0
  54. package/src/routes/popupmenu/scrollable.svelte +27 -0
  55. package/src/routes/popupmenu/showselected.svelte +4 -0
  56. package/src/test/Cards.svelte +64 -0
  57. package/{dist/ts/tests/CollapsingTable → src/test}/CollapsingTableTest.svelte +2 -2
  58. package/{dist/ts/tests/Modal → src/test}/ModalTest.svelte +3 -3
  59. package/src/test/MultiSelectTest.svelte +26 -0
  60. package/{dist/ts/tests/Actions → src/test}/Offset.svelte +2 -4
  61. package/{dist/ts/tests/PopupMenu → src/test}/PopupMenuBody.svelte +1 -1
  62. package/{dist/ts/tests/PopupMenu → src/test}/PopupMenuButtonIsParent.svelte +2 -2
  63. package/{dist/ts/tests/PopupMenu → src/test}/PopupMenuComplex.svelte +2 -2
  64. package/{dist/ts/tests/PopupMenu → src/test}/PopupMenuSimple.svelte +2 -2
  65. package/{dist/ts/tests/Actions → src/test}/Resize.svelte +2 -4
  66. package/{dist/ts/tests/Actions → src/test}/Sticky.svelte +1 -1
  67. package/static/layout.css +263 -0
  68. package/svelte.config.js +15 -0
  69. package/tests/.eslintrc.cjs +19 -0
  70. package/tests/CardLayout.test.js +41 -0
  71. package/tests/CollapsingTable.test.js +37 -0
  72. package/tests/Modal.test.js +18 -0
  73. package/tests/MultiSelect.test.js +58 -0
  74. package/tests/PopupMenu.test.js +55 -0
  75. package/tests/common.js +4 -0
  76. package/tsconfig.json +31 -0
  77. package/LICENSE +0 -21
  78. package/dist/actions/buttonify.js +0 -31
  79. package/dist/actions/buttonify.js.map +0 -1
  80. package/dist/actions/glue.js +0 -87
  81. package/dist/actions/glue.js.map +0 -1
  82. package/dist/actions/index.js +0 -20
  83. package/dist/actions/index.js.map +0 -1
  84. package/dist/actions/offset.js +0 -35
  85. package/dist/actions/offset.js.map +0 -1
  86. package/dist/actions/portal.js +0 -19
  87. package/dist/actions/portal.js.map +0 -1
  88. package/dist/actions/resize.js +0 -48
  89. package/dist/actions/resize.js.map +0 -1
  90. package/dist/actions/sticky.js +0 -93
  91. package/dist/actions/sticky.js.map +0 -1
  92. package/dist/actions/stickyfixed.js +0 -166
  93. package/dist/actions/stickyfixed.js.map +0 -1
  94. package/dist/components/CollapsingTable.svelte +0 -147
  95. package/dist/components/ConditionalWrapper.svelte +0 -38
  96. package/dist/components/FocusLock.svelte +0 -105
  97. package/dist/components/Modal.svelte +0 -52
  98. package/dist/components/PopupMenu.svelte +0 -282
  99. package/dist/components/ScreenReaderOnly.svelte +0 -25
  100. package/dist/components/index.js +0 -19
  101. package/dist/components/index.js.map +0 -1
  102. package/dist/index.js +0 -17
  103. package/dist/index.js.map +0 -1
  104. package/dist/lib/activestore.js +0 -123
  105. package/dist/lib/activestore.js.map +0 -1
  106. package/dist/lib/bodyoffset.js +0 -76
  107. package/dist/lib/bodyoffset.js.map +0 -1
  108. package/dist/lib/convertedstore.js +0 -41
  109. package/dist/lib/convertedstore.js.map +0 -1
  110. package/dist/lib/derivedstore.js +0 -65
  111. package/dist/lib/derivedstore.js.map +0 -1
  112. package/dist/lib/index.js +0 -22
  113. package/dist/lib/index.js.map +0 -1
  114. package/dist/lib/repositioned.js +0 -92
  115. package/dist/lib/repositioned.js.map +0 -1
  116. package/dist/lib/safestore.js +0 -16
  117. package/dist/lib/safestore.js.map +0 -1
  118. package/dist/lib/store.js +0 -27
  119. package/dist/lib/store.js.map +0 -1
  120. package/dist/lib/substore.js +0 -47
  121. package/dist/lib/substore.js.map +0 -1
  122. package/dist/lib/util.js +0 -16
  123. package/dist/lib/util.js.map +0 -1
  124. package/dist/ts/actions/buttonify.d.ts +0 -8
  125. package/dist/ts/actions/glue.d.ts +0 -16
  126. package/dist/ts/actions/index.d.ts +0 -7
  127. package/dist/ts/actions/offset.d.ts +0 -15
  128. package/dist/ts/actions/portal.d.ts +0 -4
  129. package/dist/ts/actions/resize.d.ts +0 -16
  130. package/dist/ts/actions/sticky.d.ts +0 -33
  131. package/dist/ts/actions/stickyfixed.d.ts +0 -25
  132. package/dist/ts/components/index.d.ts +0 -6
  133. package/dist/ts/index.d.ts +0 -4
  134. package/dist/ts/lib/activestore.d.ts +0 -60
  135. package/dist/ts/lib/bodyoffset.d.ts +0 -13
  136. package/dist/ts/lib/convertedstore.d.ts +0 -16
  137. package/dist/ts/lib/derivedstore.d.ts +0 -23
  138. package/dist/ts/lib/index.d.ts +0 -9
  139. package/dist/ts/lib/repositioned.d.ts +0 -13
  140. package/dist/ts/lib/safestore.d.ts +0 -4
  141. package/dist/ts/lib/store.d.ts +0 -16
  142. package/dist/ts/lib/substore.d.ts +0 -24
  143. package/dist/ts/lib/util.d.ts +0 -2
  144. package/dist/ts/tests/Actions/Actions.stories.d.ts +0 -1
  145. package/dist/ts/tests/CollapsingTable/CollapsingTable.stories.d.ts +0 -1
  146. package/dist/ts/tests/CollapsingTable/CollapsingTable.test.d.ts +0 -1
  147. package/dist/ts/tests/Modal/Modal.stories.d.ts +0 -1
  148. package/dist/ts/tests/Modal/Modal.test.d.ts +0 -1
  149. package/dist/ts/tests/PopupMenu/PopupMenu.stories.d.ts +0 -1
  150. package/dist/ts/tests/PopupMenu/PopupMenu.test.d.ts +0 -1
  151. package/dist/ts/tests/stores/deepstore.test.d.ts +0 -1
  152. package/dist/ts/types/CollapsingTable.d.ts +0 -8
  153. package/dist/ts/types/PopupMenu.d.ts +0 -5
  154. package/dist/ts/types/index.d.ts +0 -2
  155. package/dist/types/CollapsingTable.js +0 -3
  156. package/dist/types/CollapsingTable.js.map +0 -1
  157. package/dist/types/PopupMenu.js +0 -3
  158. package/dist/types/PopupMenu.js.map +0 -1
  159. package/dist/types/index.js +0 -15
  160. package/dist/types/index.js.map +0 -1
  161. package/esm/index.js +0 -1
  162. package/esm/package.json +0 -3
@@ -1,147 +0,0 @@
1
- <script>var _a;
2
- import { Store, classes } from '../lib';
3
- import { derived } from 'svelte/store';
4
- import DefaultPopupMenu from './PopupMenu.svelte';
5
- import ScreenReaderOnly from './ScreenReaderOnly.svelte';
6
- export let tableClass = '';
7
- export let bodyRowClass = '';
8
- export let bodyCellClass = '';
9
- export let headerRowClass = '';
10
- export let headerCellClass = '';
11
- export let menuContainerClass = '';
12
- export let menuClass = '';
13
- export let menuItemClass = '';
14
- export let menuItemHilitedClass = '';
15
- export let items;
16
- export let config = undefined;
17
- export let defaultCellWidth = 150;
18
- export let PopupMenu = DefaultPopupMenu;
19
- export let slots = $$slots;
20
- export let stickyheader = false;
21
- let columns;
22
- let width = 320;
23
- let selected;
24
- let identifyingkeys = [];
25
- $: firstrow = (_a = items === null || items === void 0 ? void 0 : items[0]) !== null && _a !== void 0 ? _a : {};
26
- $: columns = config !== null && config !== void 0 ? config : Object.keys(firstrow).map(key => ({ key }));
27
- function reactToColumns(columns) {
28
- if (!columns.some(c => c.neverhide)) {
29
- columns[0].neverhide = true;
30
- }
31
- const sortedcolumns = columns // stable sort
32
- .map((c, i) => ({ col: c, idx: i }))
33
- .sort((a, b) => ((a.col.neverhide ? 0 : 1) - (b.col.neverhide ? 0 : 1)) || a.idx - b.idx)
34
- .map(o => o.col);
35
- if (!selected) {
36
- const firstcol = sortedcolumns.find(c => !c.neverhide);
37
- selected = firstcol ? { value: firstcol.key } : undefined;
38
- }
39
- identifyingkeys = sortedcolumns.filter(c => c.neverhide).map(c => c.key);
40
- return sortedcolumns;
41
- }
42
- $: sortedcolumns = reactToColumns(columns);
43
- $: itemkeys = items.map(item => { var _a, _b; return (_b = (_a = item.id) !== null && _a !== void 0 ? _a : item._id) !== null && _b !== void 0 ? _b : identifyingkeys.map(k => item[k]).join('.'); });
44
- const state = new Store({
45
- keepcolumns: [],
46
- hiddencolumns: [],
47
- dropdowncolumn: undefined
48
- });
49
- const menuitems = derived(state, obj => obj.hiddencolumns.map(c => ({ value: c.key, label: c.title })));
50
- function react(..._) {
51
- var _a, _b, _c, _d;
52
- const selectedcol = (_a = sortedcolumns.find(c => c.key === (selected === null || selected === void 0 ? void 0 : selected.value))) !== null && _a !== void 0 ? _a : columns[1];
53
- const keepcolumns = [];
54
- const hiddencolumns = [];
55
- let used = sortedcolumns.filter(c => c.neverhide || c === selectedcol).reduce((sum, col) => { var _a; return sum + ((_a = col.width) !== null && _a !== void 0 ? _a : defaultCellWidth); }, 0);
56
- for (const col of sortedcolumns) {
57
- if (col.neverhide || col === selectedcol || used + ((_b = col.width) !== null && _b !== void 0 ? _b : defaultCellWidth) < width) {
58
- keepcolumns.push(col);
59
- if (col !== selectedcol && !col.neverhide)
60
- used += (_c = col.width) !== null && _c !== void 0 ? _c : defaultCellWidth;
61
- }
62
- else
63
- hiddencolumns.push(col);
64
- }
65
- for (const col of keepcolumns) {
66
- col.widthPercent = 100 * ((_d = col.width) !== null && _d !== void 0 ? _d : defaultCellWidth) / used;
67
- }
68
- const dropdowncolumn = hiddencolumns.length ? keepcolumns[keepcolumns.length - 1] : undefined;
69
- state.set({ keepcolumns, hiddencolumns, dropdowncolumn });
70
- }
71
- $: react(width, selected);
72
- let headers = [];
73
- $: menubuttonelement = headers[$state.keepcolumns.length - 1];
74
- </script>
75
-
76
- <div bind:clientWidth={width}>
77
- <table class={tableClass}>
78
- <thead class:stickyheader><tr class={headerRowClass}>
79
- {#each $state.keepcolumns as column, i (column.key)}
80
- <th
81
- class={classes(column.headerCellClass, headerCellClass)}
82
- class:defaultIcon={!slots.dropicon && $state.dropdowncolumn === column}
83
- bind:this={headers[i]}
84
- role={$state.dropdowncolumn === column ? 'button' : undefined }
85
- tabindex={$state.dropdowncolumn === column ? 0 : undefined }
86
- >
87
- <slot name="headercell" {column} key={column.key} title={column.title || column.key} item={undefined} value={undefined}>
88
- {column.title || column.key}
89
- </slot>
90
- {#if $state.dropdowncolumn === column}
91
- <ScreenReaderOnly>, click to choose another column to show</ScreenReaderOnly>
92
- <slot name="dropicon" {column} item={undefined} value={undefined}>
93
- <i aria-hidden="true"></i>
94
- </slot>
95
- {/if}
96
- </th>
97
- {/each}
98
- </tr></thead>
99
- <tbody>
100
- {#each items as item, i (itemkeys[i])}
101
- <tr class={bodyRowClass}>
102
- {#each $state.keepcolumns as column (column.key)}
103
- <td class={classes(column.bodyCellClass, bodyCellClass)}>
104
- <slot key={column.key} value={item[column.key]} {item}>
105
- {item[column.key]}
106
- </slot>
107
- </td>
108
- {/each}
109
- </tr>
110
- {/each}
111
- </tbody>
112
- {#if slots.footer}<tfoot><slot name="footer" item={undefined} key={undefined} value={undefined}></slot></tfoot>{/if}
113
- </table>
114
- </div>
115
- {#if $menuitems.length > 0}
116
- <svelte:component this={PopupMenu} {menuContainerClass} {menuClass} {menuItemClass} {menuItemHilitedClass} items={$menuitems} buttonelement={menubuttonelement} on:change={e => selected = e.detail}></svelte:component>
117
- {/if}
118
-
119
- <style>
120
- table { width: 100%; }
121
- th {
122
- position: relative;
123
- box-sizing: border-box;
124
- }
125
- th[role="button"] {
126
- cursor: pointer !important;
127
- }
128
- th.defaultIcon :global([role="button"]) {
129
- padding-right: 1.3em;
130
- }
131
- th.defaultIcon :global(i) {
132
- transform: translateY(-50%) rotate(45deg);
133
- border: solid black;
134
- border-width: 0 .2em .2em 0;
135
- padding: .15em;
136
- }
137
- th :global(i) {
138
- position: absolute;
139
- right: 0.4em;
140
- top: calc(50% - 0.08em);
141
- }
142
- .stickyheader th {
143
- position: sticky;
144
- top: 0;
145
- z-index: 1;
146
- }
147
- </style>
@@ -1,38 +0,0 @@
1
- <script>var __rest = (this && this.__rest) || function (s, e) {
2
- var t = {};
3
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
- t[p] = s[p];
5
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
- t[p[i]] = s[p[i]];
9
- }
10
- return t;
11
- };
12
- export let condition;
13
- export let component = undefined;
14
- export let a = false;
15
- export let span = false;
16
- export let element = undefined;
17
- $: passthrough = ((_a) => {
18
- var { condition, component, a, span, element } = _a, passthrough = __rest(_a, ["condition", "component", "a", "span", "element"]);
19
- return passthrough;
20
- })($$props);
21
- </script>
22
-
23
- {#if condition || (typeof condition === 'undefined' && component)}
24
- {#if component}
25
- <svelte:component this={component} bind:element {...passthrough}><slot></slot></svelte:component>
26
- {:else}
27
- {#if a}
28
- <!-- svelte-ignore a11y-missing-attribute -->
29
- <a bind:this={element} {...passthrough}><slot></slot></a>
30
- {:else if span}
31
- <span bind:this={element} {...passthrough}><slot></slot></span>
32
- {:else}
33
- <div bind:this={element} {...passthrough}><slot></slot></div>
34
- {/if}
35
- {/if}
36
- {:else}
37
- <slot></slot>
38
- {/if}
@@ -1,105 +0,0 @@
1
- <script context="module">const FocusLockStack = [];
2
- </script>
3
-
4
- <script>export let returnfocusto = undefined;
5
- export let initialfocus = undefined;
6
- export let hidefocus = true;
7
- export let hidefocuslabel = "focus is above modal dialog, start tabbing";
8
- export let escapable = true;
9
- let className = '';
10
- export { className as class };
11
- import { onMount, onDestroy, createEventDispatcher, tick } from 'svelte';
12
- import { tabbable } from 'tabbable';
13
- import { sleep } from 'txstate-utils';
14
- import { buttonify } from '../actions';
15
- import ScreenReaderOnly from './ScreenReaderOnly.svelte';
16
- const dispatch = createEventDispatcher();
17
- let lockelement;
18
- let abovelockelement;
19
- let active = true;
20
- let listenforescape = false;
21
- if (initialfocus)
22
- hidefocus = false;
23
- onMount(async () => {
24
- const prevFocusLock = FocusLockStack.slice(-1)[0];
25
- if (prevFocusLock)
26
- prevFocusLock.pause();
27
- FocusLockStack.push({
28
- pause: () => { active = false; },
29
- unpause: () => { active = true; }
30
- });
31
- if (typeof returnfocusto === 'undefined') {
32
- returnfocusto = document.querySelector(':focus');
33
- }
34
- await sleep(1); // sapper resets focus on page load, so we'll wait a millisecond in case our modal is on screen at load
35
- if (initialfocus) {
36
- const focusEl = lockelement.querySelector(initialfocus);
37
- if (focusEl instanceof HTMLElement)
38
- focusEl.focus();
39
- }
40
- else {
41
- setInitialFocus();
42
- }
43
- setTimeout(() => listenforescape = true, 0);
44
- });
45
- onDestroy(async () => {
46
- const wasactive = active;
47
- active = false;
48
- await tick();
49
- if (returnfocusto && wasactive) {
50
- returnfocusto.focus();
51
- }
52
- FocusLockStack.pop();
53
- const prevFocusLock = FocusLockStack.slice(-1)[0];
54
- if (prevFocusLock)
55
- prevFocusLock.unpause();
56
- });
57
- const setInitialFocus = () => {
58
- const firstfocus = tabbable(lockelement)[0];
59
- if (firstfocus && firstfocus.focus) {
60
- firstfocus.focus();
61
- }
62
- };
63
- const setLastFocus = () => {
64
- const lastfocus = tabbable(lockelement).slice(-1)[0];
65
- if (lastfocus && lastfocus.focus) {
66
- lastfocus.focus();
67
- }
68
- };
69
- const keydown = (e) => {
70
- if (active && e.key === "Escape" && escapable) {
71
- e.preventDefault();
72
- dispatch('escape');
73
- }
74
- };
75
- const focusin = (e) => {
76
- if (active && e.target instanceof HTMLElement && !(lockelement === null || lockelement === void 0 ? void 0 : lockelement.contains(e.target))) {
77
- if (e.target === abovelockelement)
78
- setLastFocus();
79
- else
80
- setInitialFocus();
81
- }
82
- };
83
- const windowclick = (_) => {
84
- if (listenforescape && active) {
85
- returnfocusto = undefined;
86
- dispatch('escape');
87
- }
88
- };
89
- </script>
90
- <svelte:window on:click={windowclick} />
91
- <div class={className} role="alertdialog" aria-modal="true" on:click|stopPropagation on:keydown|stopPropagation={keydown} on:focusin={focusin}>
92
- <div bind:this={abovelockelement} tabindex="0"></div>
93
- <div bind:this={lockelement} on:keydown={keydown}>
94
- {#if hidefocus}<div class="hiddenfocus" use:buttonify on:blur={() =>{ hidefocus = false }} on:click={() => escapable && dispatch('escape')}><ScreenReaderOnly>{hidefocuslabel}{#if escapable}, click to escape or use escape key at any time{/if}</ScreenReaderOnly></div>{/if}
95
- <slot></slot>
96
- </div>
97
- <div tabindex="0"></div>
98
- </div>
99
-
100
- <style>
101
- .hiddenfocus {
102
- opacity: 0;
103
- outline: 0;
104
- }
105
- </style>
@@ -1,52 +0,0 @@
1
- <script>export let escapable = true;
2
- export let hidefocus = true;
3
- export let hidefocuslabel = undefined;
4
- export let returnfocusto = undefined;
5
- export let initialfocus = undefined;
6
- export let containerClass = '';
7
- export let opaque = false;
8
- import FocusLock from './FocusLock.svelte';
9
- import { createEventDispatcher, onMount } from 'svelte';
10
- import { portal } from '../actions';
11
- const dispatch = createEventDispatcher();
12
- const endmodal = () => {
13
- dispatch('escape');
14
- };
15
- onMount(() => {
16
- document.body.style.marginRight = (window.innerWidth - document.body.clientWidth) + 'px';
17
- document.body.style.overflow = 'hidden';
18
- return () => {
19
- document.body.style.overflow = '';
20
- document.body.style.marginRight = '';
21
- };
22
- });
23
- </script>
24
-
25
- <div use:portal class="modal-backdrop" class:opaque on:click|stopPropagation|preventDefault={() => escapable && endmodal()}>
26
- <FocusLock class="modal-container {containerClass}" {escapable} on:escape {hidefocus} {hidefocuslabel} {returnfocusto} {initialfocus}>
27
- <slot></slot>
28
- </FocusLock>
29
- </div>
30
-
31
- <style>
32
- .modal-backdrop {
33
- position: fixed;
34
- top: 0;
35
- left: 0;
36
- width: 100vw;
37
- height: 100vh;
38
- background-color: var(--modal-bg, rgba(0, 0, 0, 0.7));
39
- z-index: 100;
40
- display: flex;
41
- justify-content: center;
42
- align-items: center
43
- }
44
- .modal-backdrop.opaque {
45
- background-color: var(--modal-bg-opaque, #4c4c4c);
46
- }
47
- .modal-backdrop :global(.modal-container) {
48
- max-width: 100vw;
49
- max-height: 100vh;
50
- overflow: auto;
51
- }
52
- </style>
@@ -1,282 +0,0 @@
1
- <script>import { glue, portal } from '../actions';
2
- import { createEventDispatcher, onDestroy, tick } from 'svelte';
3
- import { randomid } from 'txstate-utils';
4
- import { Store } from '../lib';
5
- import ScreenReaderOnly from './ScreenReaderOnly.svelte';
6
- const dispatch = createEventDispatcher();
7
- export let menushown = false;
8
- export let menuContainerClass = '';
9
- export let menuClass = '';
10
- export let menuItemClass = '';
11
- export let menuItemHilitedClass = '';
12
- export let menuItemSelectedClass = '';
13
- export let items = [];
14
- export let buttonelement;
15
- export let align = 'auto';
16
- export let cover = false;
17
- export let showSelected = true;
18
- export let width = undefined;
19
- export let computedalign = new Store({ valign: 'bottom', halign: 'left' });
20
- export let usePortal = undefined;
21
- export let emptyText = undefined;
22
- export let value = undefined;
23
- let hilited = undefined;
24
- let menuelement;
25
- let itemelements = [];
26
- const menuid = randomid();
27
- let firstactive = 0;
28
- let lastactive = items.length - 1;
29
- function hiddenItem(item) {
30
- return !!item && !showSelected && item.value === value;
31
- }
32
- async function reactToItems(..._) {
33
- var _a;
34
- firstactive = items.findIndex(itm => !itm.disabled && !hiddenItem(itm));
35
- lastactive = items.length - [...items].reverse().findIndex(itm => !itm.disabled && !hiddenItem(itm)) - 1;
36
- if (hilited && ((_a = items[hilited]) === null || _a === void 0 ? void 0 : _a.disabled))
37
- hilited = firstactive;
38
- }
39
- $: reactToItems(items, value);
40
- async function reactToMenuShown(_) {
41
- if (!buttonelement) {
42
- hilited = undefined;
43
- return;
44
- }
45
- await tick();
46
- if (!menushown) {
47
- hilited = undefined;
48
- buttonelement.removeAttribute('aria-controls');
49
- buttonelement.setAttribute('aria-expanded', 'false');
50
- }
51
- else {
52
- buttonelement.setAttribute('aria-controls', menuid);
53
- buttonelement.setAttribute('aria-expanded', 'true');
54
- }
55
- buttonelement.focus();
56
- }
57
- $: reactToMenuShown(menushown);
58
- function move(idx) {
59
- var _a;
60
- if (!menushown)
61
- return;
62
- if ((_a = items[idx]) === null || _a === void 0 ? void 0 : _a.disabled)
63
- return;
64
- hilited = Math.max(firstactive, Math.min(lastactive, idx));
65
- itemelements[hilited].scrollIntoView({ block: 'center' });
66
- buttonelement.setAttribute('aria-activedescendant', `${menuid}-${hilited}`);
67
- }
68
- function onkeydown(e) {
69
- var _a, _b, _c, _d;
70
- if (e.key === 'ArrowDown') {
71
- e.preventDefault();
72
- if (menushown) {
73
- let i = (hilited !== null && hilited !== void 0 ? hilited : firstactive - 1) + 1;
74
- while (((_a = items[i]) === null || _a === void 0 ? void 0 : _a.disabled) || hiddenItem(items[i]))
75
- i++;
76
- move(i);
77
- }
78
- else {
79
- menushown = true;
80
- move(firstactive);
81
- }
82
- }
83
- else if (e.key === 'ArrowUp') {
84
- e.preventDefault();
85
- if (menushown) {
86
- let i = (hilited !== null && hilited !== void 0 ? hilited : lastactive + 1) - 1;
87
- while (((_b = items[i]) === null || _b === void 0 ? void 0 : _b.disabled) || hiddenItem(items[i]))
88
- i--;
89
- move(i);
90
- }
91
- else {
92
- menushown = true;
93
- move(lastactive);
94
- }
95
- }
96
- else if (e.key === 'Enter') {
97
- e.preventDefault();
98
- if (menushown) {
99
- menushown = false;
100
- if (typeof hilited !== 'undefined') {
101
- value = (_c = items[hilited]) === null || _c === void 0 ? void 0 : _c.value;
102
- dispatch('change', items[hilited]);
103
- }
104
- }
105
- else {
106
- menushown = true;
107
- move(firstactive);
108
- }
109
- }
110
- else if (e.key === ' ') {
111
- // buttonelement might be a text input if this popup is searchable,
112
- // so we want to allow spaces to be entered without changing the menu situation
113
- if (menushown) {
114
- if (typeof hilited !== 'undefined') {
115
- e.preventDefault();
116
- menushown = false;
117
- value = (_d = items[hilited]) === null || _d === void 0 ? void 0 : _d.value;
118
- dispatch('change', items[hilited]);
119
- }
120
- else {
121
- if (buttonelement.tagName !== 'INPUT') {
122
- e.preventDefault();
123
- menushown = false;
124
- }
125
- }
126
- }
127
- else {
128
- if (buttonelement.tagName !== 'INPUT') {
129
- e.preventDefault();
130
- menushown = true;
131
- move(firstactive);
132
- }
133
- }
134
- }
135
- else if (menushown && e.key === 'Escape') {
136
- e.preventDefault();
137
- e.stopPropagation();
138
- menushown = false;
139
- }
140
- }
141
- function onbuttonclick(e) {
142
- e.preventDefault();
143
- menushown = !menushown;
144
- }
145
- async function onblur(e) {
146
- // tabindex=-1 on our menu elements means e.relatedTarget will be set
147
- if (!(e.relatedTarget instanceof HTMLElement && (menuelement === null || menuelement === void 0 ? void 0 : menuelement.contains(e.relatedTarget))))
148
- menushown = false;
149
- }
150
- function cleanup(element) {
151
- if (element) {
152
- element.removeEventListener('click', onbuttonclick);
153
- element.removeEventListener('keydown', onkeydown);
154
- element.removeEventListener('blur', onblur);
155
- element.removeAttribute('aria-disabled');
156
- element.removeAttribute('aria-haspopup');
157
- element.removeAttribute('aria-expanded');
158
- element.removeAttribute('aria-controls');
159
- element.removeAttribute('aria-activedescendant');
160
- }
161
- }
162
- onDestroy(() => cleanup(buttonelement));
163
- // if buttonelement changes we need to handle listeners and aria
164
- let lastbuttonelement;
165
- function reactToButtonElement(buttonelement) {
166
- cleanup(lastbuttonelement);
167
- lastbuttonelement = buttonelement;
168
- if (buttonelement) {
169
- buttonelement.setAttribute('aria-haspopup', 'listbox');
170
- buttonelement.addEventListener('click', onbuttonclick);
171
- buttonelement.addEventListener('keydown', onkeydown);
172
- buttonelement.addEventListener('blur', onblur);
173
- }
174
- }
175
- $: reactToButtonElement(buttonelement);
176
- const onclick = (item) => (e) => {
177
- e.stopPropagation();
178
- e.preventDefault();
179
- if (item.disabled)
180
- return;
181
- menushown = false;
182
- value = item.value;
183
- dispatch('change', item);
184
- };
185
- $: hasSelected = showSelected && items.some(itm => itm.value === value);
186
- </script>
187
-
188
- {#if menushown}
189
- <div use:portal={usePortal === true ? document.body : (usePortal || null)} use:glue={{ target: buttonelement, align, cover, store: computedalign }} class={menuContainerClass}>
190
- <ul bind:this={menuelement} id={menuid} role='listbox' style={width ? `width: ${width}` : ''} class={menuClass} class:hasSelected class:defaultmenu={!menuClass && !menuContainerClass} on:keydown={onkeydown}>
191
- {#each items as item, i (item.value)}
192
- {#if showSelected || item.value !== value}
193
- <li
194
- id={`${menuid}-${i}`}
195
- bind:this={itemelements[i]}
196
- class={`${menuItemClass} ${i === hilited ? menuItemHilitedClass || '' : ''} ${value === item.value ? menuItemSelectedClass || '' : ''}`}
197
- class:disabled={!!item.disabled}
198
- class:hilited={!menuItemHilitedClass && i === hilited}
199
- class:selected={showSelected && !menuItemSelectedClass && value === item.value}
200
- on:click={onclick(item)}
201
- role="option"
202
- tabindex=-1
203
- aria-disabled={item.disabled}
204
- ><slot {item} label={item.label || item.value} hilited={i === hilited} selected={value === item.value}>{item.label || item.value}</slot></li>
205
- {/if}
206
- {/each}
207
- {#if items.length === 0}
208
- <li role="option" class={`${menuItemClass} disabled`} aria-live="assertive">
209
- <slot name="noresults">
210
- {#if !emptyText}
211
- <span aria-hidden="true">{'¯\\_(ツ)_/¯'}</span><ScreenReaderOnly>{emptyText || 'empty popup menu'}</ScreenReaderOnly>
212
- {:else}
213
- {emptyText}
214
- {/if}
215
- </slot>
216
- </li>
217
- {/if}
218
- </ul>
219
- </div>
220
- {/if}
221
-
222
- <style>
223
- div {
224
- position: absolute !important;
225
- }
226
- ul {
227
- list-style: none;
228
- }
229
- ul.defaultmenu {
230
- margin: 0;
231
- padding: 0.4em;
232
- background: white;
233
- border: 1px solid slategray;
234
- border-radius: 3px;
235
- min-width: 10em;
236
- max-height: 20em;
237
- overflow-y: auto;
238
- }
239
- ul.defaultmenu li.disabled {
240
- color: rgba(0,0,0,0.6);
241
- }
242
- ul.defaultmenu::-webkit-scrollbar {
243
- appearance: none;
244
- width: 7px;
245
- }
246
- ul.defaultmenu::-webkit-scrollbar-thumb {
247
- border-radius: 4px;
248
- background-color: rgba(0,0,0,.5);
249
- box-shadow: 0 0 1px rgba(255,255,255,.5);
250
- }
251
- ul.defaultmenu::-webkit-scrollbar-track {
252
- background-color: rgba(0,0,0,.1);
253
- }
254
- li {
255
- cursor: pointer;
256
- }
257
- li.hilited {
258
- background: lightblue;
259
- }
260
- li.disabled {
261
- cursor: auto;
262
- }
263
- li.selected {
264
- position: relative;
265
- }
266
- ul.hasSelected li {
267
- padding-left: 1.4em;
268
- }
269
- li.selected:after {
270
- content: ' ';
271
- position: absolute;
272
- left: 0.5em;
273
- top: calc(50% - 0.11em);
274
- transform: translateY(-50%) rotate(38deg);
275
- display: block;
276
- height: 0.786em;
277
- width: 0.4286em;
278
- border-bottom: 0.2em solid;
279
- border-right: 0.2em solid;
280
- box-sizing: border-box;
281
- }
282
- </style>
@@ -1,25 +0,0 @@
1
- <script>export let id = undefined;
2
- export let arialive = undefined;
3
- export let ariaatomic = undefined;
4
- </script>
5
-
6
- <style>
7
- .sr-only {
8
- border: 0 !important;
9
- clip: rect(1px, 1px, 1px, 1px) !important;
10
- -webkit-clip-path: inset(50%) !important;
11
- clip-path: inset(50%) !important;
12
- height: 1px !important;
13
- margin: -1px !important;
14
- overflow: hidden !important;
15
- padding: 0 !important;
16
- position: absolute !important;
17
- width: 1px !important;
18
- white-space: nowrap !important;
19
- font-size: 20px !important;
20
- background: white !important;
21
- color: black !important;
22
- }
23
- </style>
24
-
25
- <span {id} class="sr-only" aria-live={arialive} aria-atomic={ariaatomic}><slot/></span>
@@ -1,19 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ScreenReaderOnly = exports.PopupMenu = exports.Modal = exports.ConditionalWrapper = exports.FocusLock = exports.CollapsingTable = void 0;
7
- var CollapsingTable_svelte_1 = require("./CollapsingTable.svelte");
8
- Object.defineProperty(exports, "CollapsingTable", { enumerable: true, get: function () { return __importDefault(CollapsingTable_svelte_1).default; } });
9
- var FocusLock_svelte_1 = require("./FocusLock.svelte");
10
- Object.defineProperty(exports, "FocusLock", { enumerable: true, get: function () { return __importDefault(FocusLock_svelte_1).default; } });
11
- var ConditionalWrapper_svelte_1 = require("./ConditionalWrapper.svelte");
12
- Object.defineProperty(exports, "ConditionalWrapper", { enumerable: true, get: function () { return __importDefault(ConditionalWrapper_svelte_1).default; } });
13
- var Modal_svelte_1 = require("./Modal.svelte");
14
- Object.defineProperty(exports, "Modal", { enumerable: true, get: function () { return __importDefault(Modal_svelte_1).default; } });
15
- var PopupMenu_svelte_1 = require("./PopupMenu.svelte");
16
- Object.defineProperty(exports, "PopupMenu", { enumerable: true, get: function () { return __importDefault(PopupMenu_svelte_1).default; } });
17
- var ScreenReaderOnly_svelte_1 = require("./ScreenReaderOnly.svelte");
18
- Object.defineProperty(exports, "ScreenReaderOnly", { enumerable: true, get: function () { return __importDefault(ScreenReaderOnly_svelte_1).default; } });
19
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":";;;;;;AAAA,mEAAqE;AAA5D,0IAAA,OAAO,OAAmB;AACnC,uDAAyD;AAAhD,8HAAA,OAAO,OAAa;AAC7B,yEAA2E;AAAlE,gJAAA,OAAO,OAAsB;AACtC,+CAAiD;AAAxC,sHAAA,OAAO,OAAS;AACzB,uDAAyD;AAAhD,8HAAA,OAAO,OAAa;AAC7B,qEAAuE;AAA9D,4IAAA,OAAO,OAAoB"}