@txstate-mws/svelte-components 0.0.66 → 1.0.2

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 (61) hide show
  1. package/README.md +12 -0
  2. package/dist/actions/{a11y.js → buttonify.js} +1 -1
  3. package/dist/actions/buttonify.js.map +1 -0
  4. package/dist/actions/glue.js +1 -3
  5. package/dist/actions/glue.js.map +1 -1
  6. package/dist/actions/index.js +1 -1
  7. package/dist/actions/index.js.map +1 -1
  8. package/dist/actions/portal.js +3 -7
  9. package/dist/actions/portal.js.map +1 -1
  10. package/dist/actions/stickyfixed.js +5 -5
  11. package/dist/components/CollapsingTable.svelte +3 -3
  12. package/dist/components/ConditionalWrapper.svelte +1 -1
  13. package/dist/components/FocusLock.svelte +13 -11
  14. package/dist/components/Modal.svelte +19 -11
  15. package/dist/components/PopupMenu.svelte +19 -18
  16. package/dist/components/ScreenReaderOnly.svelte +4 -5
  17. package/dist/lib/activestore.js +123 -0
  18. package/dist/lib/activestore.js.map +1 -0
  19. package/dist/lib/convertedstore.js +41 -0
  20. package/dist/lib/convertedstore.js.map +1 -0
  21. package/dist/lib/derivedstore.js +37 -25
  22. package/dist/lib/derivedstore.js.map +1 -1
  23. package/dist/lib/index.js +3 -1
  24. package/dist/lib/index.js.map +1 -1
  25. package/dist/lib/safestore.js +2 -2
  26. package/dist/lib/safestore.js.map +1 -1
  27. package/dist/lib/store.js +27 -0
  28. package/dist/lib/store.js.map +1 -0
  29. package/dist/lib/substore.js +10 -9
  30. package/dist/lib/substore.js.map +1 -1
  31. package/dist/ts/actions/{a11y.d.ts → buttonify.d.ts} +0 -0
  32. package/dist/ts/actions/glue.d.ts +1 -1
  33. package/dist/ts/actions/index.d.ts +1 -1
  34. package/dist/ts/actions/stickyfixed.d.ts +5 -5
  35. package/dist/ts/components/CollapsingTable.svelte +3 -3
  36. package/dist/ts/components/ConditionalWrapper.svelte +1 -1
  37. package/dist/ts/components/FocusLock.svelte +13 -10
  38. package/dist/ts/components/Modal.svelte +20 -11
  39. package/dist/ts/components/PopupMenu.svelte +18 -17
  40. package/dist/ts/components/ScreenReaderOnly.svelte +5 -5
  41. package/dist/ts/lib/activestore.d.ts +60 -0
  42. package/dist/ts/lib/convertedstore.d.ts +16 -0
  43. package/dist/ts/lib/derivedstore.d.ts +15 -8
  44. package/dist/ts/lib/index.d.ts +3 -1
  45. package/dist/ts/lib/safestore.d.ts +2 -2
  46. package/dist/ts/lib/store.d.ts +16 -0
  47. package/dist/ts/lib/substore.d.ts +7 -6
  48. package/dist/ts/tests/Modal/ModalTest.svelte +2 -2
  49. package/dist/ts/tests/PopupMenu/PopupMenuSimple.svelte +8 -2
  50. package/docs/CollapsingTable.md +11 -12
  51. package/docs/ConditionalWrapper.md +35 -0
  52. package/docs/Modal.md +63 -0
  53. package/docs/PopupMenu.md +31 -0
  54. package/docs/ScreenReaderOnly.md +10 -0
  55. package/docs/actions.md +76 -2
  56. package/docs/stores.md +203 -0
  57. package/package.json +17 -9
  58. package/dist/actions/a11y.js.map +0 -1
  59. package/dist/lib/deepstore.js +0 -80
  60. package/dist/lib/deepstore.js.map +0 -1
  61. package/dist/ts/lib/deepstore.d.ts +0 -42
@@ -1,53 +1,65 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DerivedStore = void 0;
4
- const deepstore_1 = require("./deepstore");
3
+ exports.derivedStore = exports.DerivedStore = void 0;
4
+ const store_1 = require("./store");
5
5
  const txstate_utils_1 = require("txstate-utils");
6
- const store_1 = require("svelte/store");
7
6
  /**
8
7
  * Watch one or more parent stores for changes. Each time, run a function to derive
9
8
  * a new state from the parent state(s). Subscribers will only be notified if the
10
9
  * derived state has changed (uses fast-deep-equal).
11
10
  *
12
11
  * If only one parent store, it's possible to use a dot-prop string as the getter.
13
- *
14
- * If you create one of these in a component, be sure to call .complete() in onDestroy
15
- * to free up memory.
16
12
  */
17
- class DerivedStore extends deepstore_1.DeepStore {
18
- constructor(store, getter) {
13
+ class DerivedStore extends store_1.Store {
14
+ constructor(store, getter, options) {
19
15
  if (typeof getter === 'string') {
20
16
  const accessor = getter;
21
17
  getter = (parentValue) => (0, txstate_utils_1.get)(parentValue, accessor);
22
18
  }
23
19
  super({});
24
20
  if (Array.isArray(store)) {
25
- const values = store.map(store_1.get);
21
+ const values = [];
22
+ let timer;
23
+ const superSet = () => super.set(getter(values));
24
+ const superSetDebounced = (options === null || options === void 0 ? void 0 : options.debounce) == null || (options === null || options === void 0 ? void 0 : options.debounce) === false || (options === null || options === void 0 ? void 0 : options.debounce) < 0
25
+ ? superSet
26
+ : () => {
27
+ clearTimeout(timer);
28
+ timer = setTimeout(superSet, options.debounce === true ? 0 : options.debounce);
29
+ };
26
30
  for (let i = 0; i < store.length; i++) {
27
- let unsubscribe;
28
- if (store instanceof deepstore_1.DeepStore) {
29
- unsubscribe = store[i].subscribe(v => {
30
- values[i] = store.clone(v);
31
- super.set(getter(values));
32
- });
31
+ const idx = i;
32
+ const st = store[i];
33
+ if (st instanceof store_1.Store) {
34
+ this.registerSource(() => st.subscribe(v => {
35
+ values[idx] = st.clone(v);
36
+ superSetDebounced();
37
+ }));
33
38
  }
34
39
  else {
35
- unsubscribe = store[i].subscribe(v => {
36
- values[i] = v;
37
- super.set(getter(values));
38
- });
40
+ this.registerSource(() => st.subscribe(v => {
41
+ values[idx] = v;
42
+ superSetDebounced();
43
+ }));
39
44
  }
40
- this.cleanup(unsubscribe);
41
45
  }
42
- super.set(getter(values));
43
46
  }
44
47
  else {
45
- const unsubscribe = store.subscribe(v => {
46
- super.set(getter(v));
47
- });
48
- this.cleanup(unsubscribe);
48
+ let timer;
49
+ const superSet = (v) => super.set(getter(v));
50
+ const superSetDebounced = (options === null || options === void 0 ? void 0 : options.debounce) == null || (options === null || options === void 0 ? void 0 : options.debounce) === false || (options === null || options === void 0 ? void 0 : options.debounce) < 0
51
+ ? superSet
52
+ : (v) => {
53
+ clearTimeout(timer);
54
+ timer = setTimeout(() => superSet(v), options.debounce === true ? 0 : options.debounce);
55
+ };
56
+ this.registerSource(() => store.subscribe(superSetDebounced));
49
57
  }
50
58
  }
51
59
  }
52
60
  exports.DerivedStore = DerivedStore;
61
+ function derivedStore(store, getter, options) {
62
+ return new DerivedStore(store, getter, options);
63
+ }
64
+ exports.derivedStore = derivedStore;
53
65
  //# sourceMappingURL=derivedstore.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"derivedstore.js","sourceRoot":"","sources":["../../src/lib/derivedstore.ts"],"names":[],"mappings":";;;AAAA,2CAAsD;AACtD,iDAAmC;AACnC,wCAA4C;AAE5C;;;;;;;;;GASG;AACH,MAAa,YAA4C,SAAQ,qBAAsB;IAIrF,YAAa,KAA8C,EAAE,MAA6E;QACxI,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;YAC9B,MAAM,QAAQ,GAAG,MAAM,CAAA;YACvB,MAAM,GAAG,CAAC,WAAgB,EAAE,EAAE,CAAC,IAAA,mBAAG,EAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;SAC1D;QACD,KAAK,CAAC,EAAS,CAAC,CAAA;QAChB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACxB,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,WAAM,CAAC,CAAA;YAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;gBACrC,IAAI,WAAW,CAAA;gBACf,IAAI,KAAK,YAAY,qBAAS,EAAE;oBAC9B,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;wBACnC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;wBAC1B,KAAK,CAAC,GAAG,CAAE,MAAyC,CAAC,MAAM,CAAC,CAAC,CAAA;oBAC/D,CAAC,CAAC,CAAA;iBACH;qBAAM;oBACL,WAAW,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;wBACnC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;wBACb,KAAK,CAAC,GAAG,CAAE,MAAyC,CAAC,MAAM,CAAC,CAAC,CAAA;oBAC/D,CAAC,CAAC,CAAA;iBACH;gBACD,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;aAC1B;YACD,KAAK,CAAC,GAAG,CAAE,MAAyC,CAAC,MAAM,CAAC,CAAC,CAAA;SAC9D;aAAM;YACL,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;gBACtC,KAAK,CAAC,GAAG,CAAE,MAAsC,CAAC,CAAC,CAAC,CAAC,CAAA;YACvD,CAAC,CAAC,CAAA;YACF,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;SAC1B;IACH,CAAC;CACF;AAnCD,oCAmCC"}
1
+ {"version":3,"file":"derivedstore.js","sourceRoot":"","sources":["../../src/lib/derivedstore.ts"],"names":[],"mappings":"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"}
package/dist/lib/index.js CHANGED
@@ -11,10 +11,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  __exportStar(require("./bodyoffset"), exports);
14
- __exportStar(require("./deepstore"), exports);
14
+ __exportStar(require("./convertedstore"), exports);
15
15
  __exportStar(require("./derivedstore"), exports);
16
+ __exportStar(require("./activestore"), exports);
16
17
  __exportStar(require("./repositioned"), exports);
17
18
  __exportStar(require("./safestore"), exports);
19
+ __exportStar(require("./store"), exports);
18
20
  __exportStar(require("./substore"), exports);
19
21
  __exportStar(require("./util"), exports);
20
22
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,+CAA4B;AAC5B,8CAA2B;AAC3B,iDAA8B;AAC9B,iDAA8B;AAC9B,8CAA2B;AAC3B,6CAA0B;AAC1B,yCAAsB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,+CAA4B;AAC5B,mDAAgC;AAChC,iDAA8B;AAC9B,gDAA6B;AAC7B,iDAA8B;AAC9B,8CAA2B;AAC3B,0CAAuB;AACvB,6CAA0B;AAC1B,yCAAsB"}
@@ -4,10 +4,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.SafeStore = void 0;
7
- const deepstore_1 = require("./deepstore");
7
+ const store_1 = require("./store");
8
8
  const rfdc_1 = __importDefault(require("rfdc"));
9
9
  const cloneDeep = (0, rfdc_1.default)();
10
- class SafeStore extends deepstore_1.DeepStore {
10
+ class SafeStore extends store_1.Store {
11
11
  clone(value) {
12
12
  return cloneDeep(value);
13
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"safestore.js","sourceRoot":"","sources":["../../src/lib/safestore.ts"],"names":[],"mappings":";;;;;;AAAA,2CAAuC;AACvC,gDAAuB;AACvB,MAAM,SAAS,GAAG,IAAA,cAAI,GAAE,CAAA;AAExB,MAAa,SAAa,SAAQ,qBAAY;IAC5C,KAAK,CAAE,KAAQ;QACb,OAAO,SAAS,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;CACF;AAJD,8BAIC"}
1
+ {"version":3,"file":"safestore.js","sourceRoot":"","sources":["../../src/lib/safestore.ts"],"names":[],"mappings":";;;;;;AAAA,mCAA+B;AAC/B,gDAAuB;AACvB,MAAM,SAAS,GAAG,IAAA,cAAI,GAAE,CAAA;AAExB,MAAa,SAAa,SAAQ,aAAQ;IACxC,KAAK,CAAE,KAAQ;QACb,OAAO,SAAS,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;CACF;AAJD,8BAIC"}
@@ -0,0 +1,27 @@
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.Store = void 0;
7
+ const fast_deep_equal_1 = __importDefault(require("fast-deep-equal"));
8
+ const activestore_1 = require("./activestore");
9
+ /**
10
+ * An alternative to svelte's "writable" that also checks deep equality (fast-deep-equal) before
11
+ * notifying subscribers. A writable will notify subscribers after a shallow equality check, which
12
+ * only works for scalars.
13
+ *
14
+ * Note that this strategy is weak against mutable state updates:
15
+ * store.update(v => { v.someprop = 'newvalue'; return v })
16
+ *
17
+ * This line would NOT notify subscribers because the state will be compared against
18
+ * itself and always found to be equal. If you are making updates in a mutable fashion,
19
+ * use a SafeStore instead.
20
+ */
21
+ class Store extends activestore_1.ActiveStore {
22
+ equal(a, b) {
23
+ return (0, fast_deep_equal_1.default)(a, b);
24
+ }
25
+ }
26
+ exports.Store = Store;
27
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/lib/store.ts"],"names":[],"mappings":";;;;;;AAAA,sEAAuC;AACvC,+CAA2C;AAE3C;;;;;;;;;;;GAWG;AACH,MAAa,KAAS,SAAQ,yBAAc;IAC1C,KAAK,CAAE,CAAI,EAAE,CAAI;QACf,OAAO,IAAA,yBAAS,EAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACxB,CAAC;CACF;AAJD,sBAIC"}
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SubStore = void 0;
3
+ exports.subStore = exports.SubStore = void 0;
4
4
  const txstate_utils_1 = require("txstate-utils");
5
- const deepstore_1 = require("./deepstore");
5
+ const store_1 = require("./store");
6
6
  /**
7
7
  * Create a store that represents a part of a larger store. Updates to the parent store will propagate
8
8
  * down to the SubStore as appropriate, and updates to the SubStore will propagate
@@ -14,23 +14,20 @@ const deepstore_1 = require("./deepstore");
14
14
  * generated. For example, a parent store containing state { deep: { value: 'here' }, hello: 'world' }
15
15
  * could be used with the getter string "deep.value". The SubStore's initial state would be "here", and
16
16
  * updating it to "there" would update the parent store state to { deep: { value: 'there' }, hello: 'world' }
17
- *
18
- * If you create one of these in a component, be sure to call .complete() in onDestroy to free up memory.
19
17
  */
20
- class SubStore extends deepstore_1.DeepStore {
18
+ class SubStore extends store_1.Store {
21
19
  constructor(store, getter, setter) {
20
+ super({});
22
21
  if (typeof getter === 'string') {
23
22
  const accessor = getter;
24
23
  getter = parentValue => (0, txstate_utils_1.get)(parentValue, accessor);
25
24
  setter = (newValue, parentValue) => (0, txstate_utils_1.set)(parentValue, accessor, newValue);
26
25
  }
27
- super({});
28
26
  this.parentStore = store;
29
27
  this.setter = setter;
30
- const unsubscribe = store.subscribe(v => {
28
+ this.registerSource(() => store.subscribe(v => {
31
29
  super.set(getter(v));
32
- });
33
- this.cleanup(unsubscribe);
30
+ }));
34
31
  }
35
32
  set(value) {
36
33
  this.parentStore.update(parentValue => this.setter(value, parentValue));
@@ -43,4 +40,8 @@ class SubStore extends deepstore_1.DeepStore {
43
40
  }
44
41
  }
45
42
  exports.SubStore = SubStore;
43
+ function subStore(store, getter, setter) {
44
+ return new SubStore(store, getter, setter);
45
+ }
46
+ exports.subStore = subStore;
46
47
  //# sourceMappingURL=substore.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"substore.js","sourceRoot":"","sources":["../../src/lib/substore.ts"],"names":[],"mappings":";;;AAAA,iDAAwC;AACxC,2CAAwD;AAExD;;;;;;;;;;;;;GAaG;AACH,MAAa,QAAoC,SAAQ,qBAAkB;IAMzE,YAAa,KAAkC,EAAE,MAA+C,EAAE,MAA0D;QAC1J,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;YAC9B,MAAM,QAAQ,GAAG,MAAM,CAAA;YACvB,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,IAAA,mBAAG,EAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;YAClD,MAAM,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,CAAC,IAAA,mBAAG,EAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;SACzE;QACD,KAAK,CAAC,EAAS,CAAC,CAAA;QAChB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAA;QACxB,IAAI,CAAC,MAAM,GAAG,MAAO,CAAA;QACrB,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;YACtC,KAAK,CAAC,GAAG,CAAE,MAAc,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/B,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IAC3B,CAAC;IAED,GAAG,CAAE,KAAc;QACjB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAA;IACzE,CAAC;IAED,KAAK,CAAE,KAAc;;QACnB,6EAA6E;QAC7E,sDAAsD;QACtD,OAAO,MAAA,MAAA,MAAC,IAAI,CAAC,WAA8B,0CAAE,KAAK,mDAAG,KAAK,CAAC,mCAAI,KAAK,CAAA;IACtE,CAAC;CACF;AA9BD,4BA8BC"}
1
+ {"version":3,"file":"substore.js","sourceRoot":"","sources":["../../src/lib/substore.ts"],"names":[],"mappings":";;;AAAA,iDAAwC;AACxC,mCAA+B;AAG/B;;;;;;;;;;;GAWG;AACH,MAAa,QAAoC,SAAQ,aAAc;IAIrE,YAAa,KAAkC,EAAE,MAAgE,EAAE,MAA0D;QAC3K,KAAK,CAAC,EAAS,CAAC,CAAA;QAChB,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;YAC9B,MAAM,QAAQ,GAAG,MAAM,CAAA;YACvB,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,IAAA,mBAAG,EAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;YAClD,MAAM,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,CAAC,IAAA,mBAAG,EAAC,WAAW,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;SACzE;QACD,IAAI,CAAC,WAAW,GAAG,KAAK,CAAA;QACxB,IAAI,CAAC,MAAM,GAAG,MAAO,CAAA;QACrB,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;YAC5C,KAAK,CAAC,GAAG,CAAE,MAAc,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/B,CAAC,CAAC,CAAC,CAAA;IACL,CAAC;IAED,GAAG,CAAE,KAAc;QACjB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAA;IACzE,CAAC;IAED,KAAK,CAAE,KAAc;;QACnB,6EAA6E;QAC7E,sDAAsD;QACtD,OAAO,MAAA,MAAA,MAAC,IAAI,CAAC,WAA0B,0CAAE,KAAK,mDAAG,KAAK,CAAC,mCAAI,KAAK,CAAA;IAClE,CAAC;CACF;AA3BD,4BA2BC;AAKD,SAAgB,QAAQ,CAAwB,KAAkC,EAAE,MAAgE,EAAE,MAA0D;IAC9M,OAAO,IAAI,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAC5C,CAAC;AAFD,4BAEC"}
File without changes
@@ -12,5 +12,5 @@ export interface GlueAlignStore {
12
12
  }
13
13
  export declare function glue(el: HTMLElement, { target, align, cover, store }: GlueArgs): {
14
14
  update({ target: utarget, align: ualign, cover: ucover, store: ustore }: GlueArgs): void;
15
- destroy(): void;
15
+ destroy: () => void;
16
16
  };
@@ -1,4 +1,4 @@
1
- export * from './a11y';
1
+ export * from './buttonify';
2
2
  export * from './glue';
3
3
  export * from './offset';
4
4
  export * from './portal';
@@ -1,6 +1,6 @@
1
1
  import { StickyArgs } from './sticky';
2
2
  /**
3
- * An implementation of stickyness based on `transform: translateY()`. Only use when
3
+ * An implementation of stickyness based on `positon: fixed`. Only use when
4
4
  * `position: sticky` won't work for you. If `position: sticky` does work for you, use it,
5
5
  * it performs better.
6
6
  *
@@ -10,10 +10,10 @@ import { StickyArgs } from './sticky';
10
10
  * 3) it always stays within the boundaries of the closest parent element that has a `position`
11
11
  * * use:sticky accepts a `target` element as a parameter, defining the bounding container
12
12
  *
13
- * Note that this implementation sacrifices simplicity for animation performance. It does a lot of
14
- * work like cloning the element you place it on, placing the cloned element next to yours in the DOM,
15
- * setting widths to match between them, watching for mutations to keep them in sync, etc. Some of
16
- * this work may get foiled if you have a complex html/css/js situation.
13
+ * Note that this implementation gets great animation performance at the cost of extra complexity.
14
+ * It does a lot of work like cloning the element you place it on, placing the cloned element next
15
+ * to yours in the DOM, setting widths to match between them, watching for mutations to keep them
16
+ * in sync, etc. Some of this work may get foiled if you have a complex html/css/js situation.
17
17
  *
18
18
  * You may also want to try use:sticky. It is based on setting `transform: translateY()` as appropriate,
19
19
  * and is less fragile than this. However, it cannot do its work before the scroll on mobile, only after,
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { DeepStore, classes } from '../lib'
2
+ import { Store, classes } from '../lib'
3
3
  import type { CollapsingTableColumn, PopupMenuItem } from '../types'
4
4
  import { derived } from 'svelte/store'
5
5
  import DefaultPopupMenu from './PopupMenu.svelte'
@@ -45,7 +45,7 @@
45
45
 
46
46
  $: itemkeys = items.map(item => item.id ?? item._id ?? identifyingkeys.map(k => item[k]).join('.'))
47
47
 
48
- const state = new DeepStore({
48
+ const state = new Store({
49
49
  keepcolumns: [] as (CollapsingTableColumn & { widthPercent?: number })[],
50
50
  hiddencolumns: [] as CollapsingTableColumn[],
51
51
  dropdowncolumn: undefined as (CollapsingTableColumn & { widthPercent?: number }) | undefined
@@ -113,7 +113,7 @@
113
113
  </table>
114
114
  </div>
115
115
  {#if $menuitems.length > 0}
116
- <svelte:component this={PopupMenu} {menuContainerClass} {menuClass} {menuItemClass} {menuItemHilitedClass} items={$menuitems} buttonelement={menubuttonelement} bind:selected></svelte:component>
116
+ <svelte:component this={PopupMenu} {menuContainerClass} {menuClass} {menuItemClass} {menuItemHilitedClass} items={$menuitems} buttonelement={menubuttonelement} on:change={e => selected = e.detail}></svelte:component>
117
117
  {/if}
118
118
 
119
119
  <style>
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- export let condition: boolean|undefined = undefined
2
+ export let condition: boolean|undefined
3
3
  export let component: Function|undefined = undefined
4
4
  export let a = false
5
5
  export let span = false
@@ -13,14 +13,16 @@
13
13
 
14
14
  import { onMount, onDestroy, createEventDispatcher, tick } from 'svelte'
15
15
  import { tabbable } from 'tabbable'
16
+ import { sleep } from 'txstate-utils'
16
17
  import { buttonify } from '../actions'
17
18
  import ScreenReaderOnly from './ScreenReaderOnly.svelte'
18
19
  const dispatch = createEventDispatcher()
19
20
  let lockelement: HTMLElement
20
21
  let abovelockelement: HTMLElement
21
22
  let active = true
23
+ let listenforescape = false
22
24
  if (initialfocus) hidefocus = false
23
- onMount(() => {
25
+ onMount(async () => {
24
26
  const prevFocusLock = FocusLockStack.slice(-1)[0]
25
27
  if (prevFocusLock) prevFocusLock.pause()
26
28
  FocusLockStack.push({
@@ -30,25 +32,20 @@
30
32
  if (typeof returnfocusto === 'undefined') {
31
33
  returnfocusto = document.querySelector(':focus') as HTMLElement
32
34
  }
35
+ await sleep(1) // sapper resets focus on page load, so we'll wait a millisecond in case our modal is on screen at load
33
36
  if (initialfocus) {
34
37
  const focusEl = lockelement.querySelector(initialfocus)
35
38
  if (focusEl instanceof HTMLElement) focusEl.focus()
36
39
  } else {
37
40
  setInitialFocus()
38
41
  }
42
+ setTimeout(() => listenforescape = true, 0)
39
43
  })
40
44
  onDestroy(async () => {
41
45
  const wasactive = active
42
- let focuswasinside
43
- try {
44
- focuswasinside = lockelement.matches(':focus-within')
45
- } catch (e: any) {
46
- // browser doesn't support :focus-within
47
- focuswasinside = true
48
- }
49
46
  active = false
50
47
  await tick()
51
- if (returnfocusto && wasactive && focuswasinside) {
48
+ if (returnfocusto && wasactive) {
52
49
  returnfocusto.focus()
53
50
  }
54
51
  FocusLockStack.pop()
@@ -79,8 +76,14 @@
79
76
  else setInitialFocus()
80
77
  }
81
78
  }
79
+ const windowclick = (_: MouseEvent) => {
80
+ if (listenforescape && active) {
81
+ returnfocusto = undefined
82
+ dispatch('escape')
83
+ }
84
+ }
82
85
  </script>
83
-
86
+ <svelte:window on:click={windowclick} />
84
87
  <div class={className} role="alertdialog" aria-modal="true" on:click|stopPropagation on:keydown|stopPropagation={keydown} on:focusin={focusin}>
85
88
  <div bind:this={abovelockelement} tabindex="0"></div>
86
89
  <div bind:this={lockelement} on:keydown={keydown}>
@@ -1,26 +1,31 @@
1
1
  <script lang="ts">
2
- export let lockbackdrop = false
2
+ export let escapable = true
3
3
  export let hidefocus = true
4
4
  export let hidefocuslabel: string|undefined = undefined
5
5
  export let returnfocusto: HTMLElement|undefined = undefined
6
6
  export let initialfocus: string|undefined = undefined
7
+ export let containerClass = ''
8
+ export let opaque = false
7
9
  import FocusLock from './FocusLock.svelte'
8
10
  import { createEventDispatcher, onMount } from 'svelte'
9
11
  import { portal } from '../actions';
12
+
10
13
  const dispatch = createEventDispatcher()
11
14
  const endmodal = () => {
12
- dispatch('dismiss')
15
+ dispatch('escape')
13
16
  }
14
17
  onMount(() => {
18
+ document.body.style.marginRight = (window.innerWidth - document.body.clientWidth) + 'px'
15
19
  document.body.style.overflow = 'hidden'
16
20
  return () => {
17
21
  document.body.style.overflow = ''
22
+ document.body.style.marginRight = ''
18
23
  }
19
24
  })
20
25
  </script>
21
26
 
22
- <div use:portal class="modal-backdrop" on:click={() => lockbackdrop || endmodal()}>
23
- <FocusLock class="modal-container" escapable={!lockbackdrop} on:escape={endmodal} {hidefocus} {hidefocuslabel} {returnfocusto} {initialfocus} on:escape={() => lockbackdrop || endmodal()}>
27
+ <div use:portal class="modal-backdrop" class:opaque on:click|stopPropagation|preventDefault={() => escapable && endmodal()}>
28
+ <FocusLock class="modal-container {containerClass}" {escapable} on:escape {hidefocus} {hidefocuslabel} {returnfocusto} {initialfocus}>
24
29
  <slot></slot>
25
30
  </FocusLock>
26
31
  </div>
@@ -30,16 +35,20 @@
30
35
  position: fixed;
31
36
  top: 0;
32
37
  left: 0;
33
- width: 100%;
34
- height: 100%;
38
+ width: 100vw;
39
+ height: 100vh;
35
40
  background-color: var(--modal-bg, rgba(0, 0, 0, 0.7));
36
- overflow: auto;
37
41
  z-index: 100;
42
+ display: flex;
43
+ justify-content: center;
44
+ align-items: center
45
+ }
46
+ .modal-backdrop.opaque {
47
+ background-color: var(--modal-bg-opaque, #4c4c4c);
38
48
  }
39
49
  .modal-backdrop :global(.modal-container) {
40
- position: absolute;
41
- left: 50%;
42
- top: 50%;
43
- transform: translate(-50%, -50%);
50
+ max-width: 100vw;
51
+ max-height: 100vh;
52
+ overflow: auto;
44
53
  }
45
54
  </style>
@@ -4,7 +4,7 @@
4
4
  import { createEventDispatcher, onDestroy, tick } from 'svelte'
5
5
  import { randomid } from 'txstate-utils'
6
6
  import type { PopupMenuItem } from '../types'
7
- import { DeepStore, SettableSubject } from '../lib'
7
+ import { Store } from '../lib'
8
8
  import ScreenReaderOnly from './ScreenReaderOnly.svelte'
9
9
  const dispatch = createEventDispatcher()
10
10
 
@@ -20,12 +20,12 @@
20
20
  export let cover = false
21
21
  export let showSelected = true
22
22
  export let width:string|undefined = undefined
23
- export let computedalign: SettableSubject<GlueAlignStore> = new DeepStore<GlueAlignStore>({ valign: 'bottom', halign: 'left' })
23
+ export let computedalign = new Store<GlueAlignStore>({ valign: 'bottom', halign: 'left' })
24
24
  export let usePortal: HTMLElement|true|undefined = undefined
25
25
  export let emptyText: string|undefined = undefined
26
- export let hilited: number|undefined = undefined
27
- export let selected: PopupMenuItem|undefined = undefined
26
+ export let value: string|undefined = undefined
28
27
 
28
+ let hilited: number|undefined = undefined
29
29
  let menuelement: HTMLElement|undefined
30
30
  let itemelements: HTMLElement[] = []
31
31
  const menuid = randomid()
@@ -33,7 +33,7 @@
33
33
  let lastactive = items.length - 1
34
34
 
35
35
  function hiddenItem (item: PopupMenuItem) {
36
- return !!item && !showSelected && item.value === selected?.value
36
+ return !!item && !showSelected && item.value === value
37
37
  }
38
38
 
39
39
  async function reactToItems (..._: any[]) {
@@ -41,7 +41,7 @@
41
41
  lastactive = items.length - [...items].reverse().findIndex(itm => !itm.disabled && !hiddenItem(itm)) - 1
42
42
  if (hilited && items[hilited]?.disabled) hilited = firstactive
43
43
  }
44
- $: reactToItems(items, selected)
44
+ $: reactToItems(items, value)
45
45
 
46
46
  async function reactToMenuShown (_: boolean) {
47
47
  if (!buttonelement) {
@@ -95,8 +95,8 @@
95
95
  if (menushown) {
96
96
  menushown = false
97
97
  if (typeof hilited !== 'undefined') {
98
- selected = items[hilited]
99
- dispatch('change', items[hilited].value)
98
+ value = items[hilited]?.value
99
+ dispatch('change', items[hilited])
100
100
  }
101
101
  } else {
102
102
  menushown = true
@@ -109,8 +109,8 @@
109
109
  if (typeof hilited !== 'undefined') {
110
110
  e.preventDefault()
111
111
  menushown = false
112
- selected = items[hilited]
113
- dispatch('change', items[hilited].value)
112
+ value = items[hilited]?.value
113
+ dispatch('change', items[hilited])
114
114
  } else {
115
115
  if (buttonelement.tagName !== 'INPUT') {
116
116
  e.preventDefault()
@@ -146,6 +146,7 @@
146
146
  element.removeEventListener('click', onbuttonclick)
147
147
  element.removeEventListener('keydown', onkeydown)
148
148
  element.removeEventListener('blur', onblur)
149
+ element.removeAttribute('aria-disabled')
149
150
  element.removeAttribute('aria-haspopup')
150
151
  element.removeAttribute('aria-expanded')
151
152
  element.removeAttribute('aria-controls')
@@ -174,30 +175,30 @@
174
175
  e.preventDefault()
175
176
  if (item.disabled) return
176
177
  menushown = false
177
- selected = item
178
- dispatch('change', item.value)
178
+ value = item.value
179
+ dispatch('change', item)
179
180
  }
180
181
 
181
- $: hasSelected = showSelected && !!items.find(itm => itm.value === selected?.value)
182
+ $: hasSelected = showSelected && items.some(itm => itm.value === value)
182
183
  </script>
183
184
 
184
185
  {#if menushown}
185
186
  <div use:portal={usePortal === true ? document.body : (usePortal || null)} use:glue={{ target: buttonelement, align, cover, store: computedalign }} class={menuContainerClass}>
186
187
  <ul bind:this={menuelement} id={menuid} role='listbox' style={width ? `width: ${width}` : ''} class={menuClass} class:hasSelected class:defaultmenu={!menuClass && !menuContainerClass} on:keydown={onkeydown}>
187
188
  {#each items as item, i (item.value)}
188
- {#if showSelected || !selected || item.value !== selected.value}
189
+ {#if showSelected || item.value !== value}
189
190
  <li
190
191
  id={`${menuid}-${i}`}
191
192
  bind:this={itemelements[i]}
192
- class={`${menuItemClass} ${i === hilited ? menuItemHilitedClass || '' : ''} ${selected && selected.value === item.value ? menuItemSelectedClass || '' : ''}`}
193
+ class={`${menuItemClass} ${i === hilited ? menuItemHilitedClass || '' : ''} ${value === item.value ? menuItemSelectedClass || '' : ''}`}
193
194
  class:disabled={!!item.disabled}
194
195
  class:hilited={!menuItemHilitedClass && i === hilited}
195
- class:selected={showSelected && !menuItemSelectedClass && selected && selected.value === item.value}
196
+ class:selected={showSelected && !menuItemSelectedClass && value === item.value}
196
197
  on:click={onclick(item)}
197
198
  role="option"
198
199
  tabindex=-1
199
200
  aria-disabled={item.disabled}
200
- ><slot {item} label={item.label || item.value} hilited={i === hilited} selected={selected && selected.value === item.value}>{item.label || item.value}</slot></li>
201
+ ><slot {item} label={item.label || item.value} hilited={i === hilited} selected={value === item.value}>{item.label || item.value}</slot></li>
201
202
  {/if}
202
203
  {/each}
203
204
  {#if items.length === 0}
@@ -1,7 +1,7 @@
1
- <script>
2
- export let id = ''
3
- export let arialive = ''
4
- export let ariaatomic = ''
1
+ <script lang="ts">
2
+ export let id: string|undefined = undefined
3
+ export let arialive: svelte.JSX.AriaAttributes['aria-live'] = undefined
4
+ export let ariaatomic: svelte.JSX.AriaAttributes['aria-atomic'] = undefined
5
5
  </script>
6
6
 
7
7
  <style>
@@ -23,4 +23,4 @@
23
23
  }
24
24
  </style>
25
25
 
26
- <span id={id} class="sr-only" aria-live={arialive} aria-atomic={ariaatomic}><slot/></span>
26
+ <span {id} class="sr-only" aria-live={arialive} aria-atomic={ariaatomic}><slot/></span>
@@ -0,0 +1,60 @@
1
+ import { Writable } from 'svelte/store';
2
+ export interface UsableSubject<T> {
3
+ subscribe: (observer: (value: T) => void) => () => void;
4
+ }
5
+ export interface WritableSubject<T> extends UsableSubject<T> {
6
+ update: (updater: (value: T) => T) => void;
7
+ }
8
+ export interface SettableSubject<T> extends WritableSubject<T> {
9
+ set: (value: T) => void;
10
+ }
11
+ export declare function isUsable<T>(value: T | UsableSubject<T> | undefined): value is UsableSubject<T>;
12
+ export declare function isWritable<T>(value: T | UsableSubject<T> | undefined): value is WritableSubject<T>;
13
+ export declare function isSettable<T>(value: T | UsableSubject<T> | undefined): value is SettableSubject<T>;
14
+ /**
15
+ * An alternative to svelte's "writable" that does not check equality before notifying
16
+ * subscribers. A writable will notify subscribers after a shallow equality check, which
17
+ * does not work with mutated states:
18
+ * store.update(v => { v.someprop = 'newvalue'; return v })
19
+ *
20
+ * With a writable, this line would NOT notify subscribers because the state will be compared
21
+ * against itself and always found to be equal.
22
+ *
23
+ * An alternative to this store type is SafeStore, which will do a deep equality check but
24
+ * clone data so that it is safe against mutations. It costs more CPU cycles but results in
25
+ * fewer notifications to subscribers which could be an overall win.
26
+ */
27
+ export declare class ActiveStore<T> implements Writable<T> {
28
+ protected value: T;
29
+ protected subscribers: Map<string, (s: T) => void>;
30
+ private cleanups;
31
+ private sourceInits;
32
+ constructor(value: T);
33
+ clone(value: T): T;
34
+ equal(a: T, b: T): boolean;
35
+ set(value: T): void;
36
+ update(updater: (value: T) => T): void;
37
+ subscribe(run: (s: T) => any): () => void;
38
+ /**
39
+ * Provided as a last ditch avenue to clean up memory after rogue subscribers forget
40
+ * to unsubscribe themselves. For example, in an SSR environment one could clear out
41
+ * global stores anytime a request finishes and no other requests are being processed.
42
+ */
43
+ clearSubscribers(): void;
44
+ /**
45
+ * Stores that subscribe to external events should set it up with a start/stop mentality
46
+ * so that the external events can be unsubscribed when the store itself has no listeners
47
+ * to notify. This helps ensure unused stores can be garbage collected.
48
+ *
49
+ * To do this, pass registerSource a function that initializes the subscription to the external
50
+ * event, and returns a function that can unsubscribe from the external event. This parent
51
+ * class will take care of running those functions at appropriate times.
52
+ */
53
+ protected registerSource(fn: () => () => void): void;
54
+ /**
55
+ * Provided in case a child class has a need to change out the external resources
56
+ */
57
+ protected unregisterSources(): void;
58
+ private subscribeToSources;
59
+ private unsubscribeFromSources;
60
+ }
@@ -0,0 +1,16 @@
1
+ import { Store } from './store';
2
+ import { UsableSubject } from './activestore';
3
+ /**
4
+ * A store that allows you to pass in a traditional svelte store in the constructor.
5
+ *
6
+ * Updates to the original store will be sent to subscribers of this store, but only after a deep equality check.
7
+ *
8
+ * Updates to this store will also be sent to the original store after a deep equality check.
9
+ */
10
+ export declare class ConvertedStore<T> extends Store<T> {
11
+ private valueStore;
12
+ private pause;
13
+ constructor(value: UsableSubject<T>);
14
+ set(value: T): void;
15
+ }
16
+ export declare function convertStore<T>(store: UsableSubject<T>): ConvertedStore<T>;