@pistonite/pure 0.28.0 → 0.29.1

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 (96) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +23 -4
  3. package/dist/_dts_/src/log/index.d.ts +37 -0
  4. package/dist/_dts_/src/log/index.d.ts.map +1 -0
  5. package/dist/_dts_/src/log/logger.d.ts +27 -0
  6. package/dist/_dts_/src/log/logger.d.ts.map +1 -0
  7. package/dist/_dts_/src/memory/cell.d.ts +25 -0
  8. package/dist/_dts_/src/memory/cell.d.ts.map +1 -0
  9. package/dist/_dts_/src/memory/emp.d.ts +87 -0
  10. package/dist/_dts_/src/memory/emp.d.ts.map +1 -0
  11. package/dist/_dts_/src/memory/idgen.d.ts +18 -0
  12. package/dist/_dts_/src/memory/idgen.d.ts.map +1 -0
  13. package/dist/_dts_/src/memory/index.d.ts +10 -0
  14. package/dist/_dts_/src/memory/index.d.ts.map +1 -0
  15. package/dist/_dts_/src/memory/persist.d.ts +38 -0
  16. package/dist/_dts_/src/memory/persist.d.ts.map +1 -0
  17. package/dist/_dts_/src/result/index.d.ts +191 -0
  18. package/dist/_dts_/src/result/index.d.ts.map +1 -0
  19. package/dist/_dts_/src/sync/RwLock.d.ts +30 -0
  20. package/dist/_dts_/src/sync/RwLock.d.ts.map +1 -0
  21. package/dist/_dts_/src/sync/batch.d.ts +112 -0
  22. package/dist/_dts_/src/sync/batch.d.ts.map +1 -0
  23. package/dist/_dts_/src/sync/capture.d.ts +11 -0
  24. package/dist/_dts_/src/sync/capture.d.ts.map +1 -0
  25. package/dist/_dts_/src/sync/debounce.d.ts +105 -0
  26. package/dist/_dts_/src/sync/debounce.d.ts.map +1 -0
  27. package/dist/_dts_/src/sync/index.d.ts +15 -0
  28. package/dist/_dts_/src/sync/index.d.ts.map +1 -0
  29. package/dist/_dts_/src/sync/latest.d.ts +86 -0
  30. package/dist/_dts_/src/sync/latest.d.ts.map +1 -0
  31. package/dist/_dts_/src/sync/mutex.d.ts +14 -0
  32. package/dist/_dts_/src/sync/mutex.d.ts.map +1 -0
  33. package/dist/_dts_/src/sync/once.d.ts +84 -0
  34. package/dist/_dts_/src/sync/once.d.ts.map +1 -0
  35. package/dist/_dts_/src/sync/serial.d.ts +162 -0
  36. package/dist/_dts_/src/sync/serial.d.ts.map +1 -0
  37. package/dist/_dts_/src/sync/util.d.ts +19 -0
  38. package/dist/_dts_/src/sync/util.d.ts.map +1 -0
  39. package/dist/log/index.js +57 -0
  40. package/dist/log/index.js.map +1 -0
  41. package/dist/memory/index.js +92 -0
  42. package/dist/memory/index.js.map +1 -0
  43. package/dist/result/index.js +29 -0
  44. package/dist/result/index.js.map +1 -0
  45. package/dist/sync/index.js +252 -0
  46. package/dist/sync/index.js.map +1 -0
  47. package/package.json +22 -13
  48. package/src/env.d.ts +1 -0
  49. package/src/log/index.ts +36 -11
  50. package/src/log/logger.ts +93 -115
  51. package/src/memory/cell.ts +21 -11
  52. package/src/memory/emp.ts +34 -23
  53. package/src/memory/idgen.test.ts +1 -1
  54. package/src/memory/index.ts +1 -4
  55. package/src/memory/persist.ts +9 -12
  56. package/src/result/index.ts +12 -4
  57. package/src/sync/batch.test.ts +1 -1
  58. package/src/sync/batch.ts +12 -17
  59. package/src/sync/capture.ts +2 -0
  60. package/src/sync/debounce.test.ts +1 -1
  61. package/src/sync/debounce.ts +12 -15
  62. package/src/sync/index.ts +2 -3
  63. package/src/sync/latest.test.ts +1 -1
  64. package/src/sync/latest.ts +19 -16
  65. package/src/sync/once.test.ts +1 -1
  66. package/src/sync/once.ts +13 -8
  67. package/src/sync/serial.test.ts +1 -1
  68. package/src/sync/serial.ts +14 -12
  69. package/src/sync/util.ts +2 -2
  70. package/src/fs/FsError.ts +0 -55
  71. package/src/fs/FsFile.ts +0 -67
  72. package/src/fs/FsFileImpl.ts +0 -219
  73. package/src/fs/FsFileMgr.ts +0 -29
  74. package/src/fs/FsFileStandalone.ts +0 -21
  75. package/src/fs/FsFileStandaloneImplFileAPI.ts +0 -54
  76. package/src/fs/FsFileStandaloneImplHandleAPI.ts +0 -147
  77. package/src/fs/FsFileSystem.ts +0 -71
  78. package/src/fs/FsFileSystemInternal.ts +0 -30
  79. package/src/fs/FsImplEntryAPI.ts +0 -149
  80. package/src/fs/FsImplFileAPI.ts +0 -116
  81. package/src/fs/FsImplHandleAPI.ts +0 -199
  82. package/src/fs/FsOpen.ts +0 -271
  83. package/src/fs/FsOpenFile.ts +0 -256
  84. package/src/fs/FsPath.ts +0 -137
  85. package/src/fs/FsSave.ts +0 -216
  86. package/src/fs/FsSupportStatus.ts +0 -87
  87. package/src/fs/index.ts +0 -123
  88. package/src/log/internal.ts +0 -14
  89. package/src/memory/async_erc.ts +0 -186
  90. package/src/memory/erc.test.ts +0 -258
  91. package/src/memory/erc.ts +0 -320
  92. package/src/pref/dark.ts +0 -151
  93. package/src/pref/device.ts +0 -118
  94. package/src/pref/index.ts +0 -13
  95. package/src/pref/inject_style.ts +0 -22
  96. package/src/pref/locale.ts +0 -296
package/src/memory/erc.ts DELETED
@@ -1,320 +0,0 @@
1
- /**
2
- * A holder for an externally ref-counted object.
3
- *
4
- * See {@link makeErcType} for how to use
5
- * @deprecated use Emp
6
- */
7
- export type Erc<TName, TRepr = number> = {
8
- readonly type: TName;
9
-
10
- /**
11
- * Underlying object representation.
12
- *
13
- * The repr should not be undefinable. undefined means nullptr
14
- */
15
- readonly value: TRepr | undefined;
16
-
17
- /**
18
- * Free the underlying object.
19
- *
20
- * All weak references will be invalidated, and this Erc will become
21
- * empty
22
- */
23
- free: () => void;
24
-
25
- /**
26
- * Assign a new value to this Erc.
27
- *
28
- * The old value will be freed, and all weak references will be invalidated.
29
- */
30
- assign: (value: TRepr | undefined) => void;
31
-
32
- /**
33
- * Take the inner value without freeing it.
34
- *
35
- * All weak references will be invalidated, and this Erc will become
36
- * empty
37
- */
38
- take: () => TRepr | undefined;
39
-
40
- /**
41
- * Create a weak reference to the inner value.
42
- *
43
- * When this Erc is freed, all weak references will be invalidated.
44
- */
45
- getWeak: () => ErcRef<TName, TRepr>;
46
-
47
- /**
48
- * Create a strong reference to the inner value, essentially
49
- * incrementing the ref count.
50
- */
51
- getStrong: () => Erc<TName, TRepr>;
52
- };
53
-
54
- /**
55
- * Weak reference to an externally ref-counted object.
56
- *
57
- * See {@link makeErcType} for how to use
58
- * @deprecated use Emp
59
- */
60
- export type ErcRef<TName, TRepr = number> = {
61
- readonly type: TName;
62
-
63
- /**
64
- * The underlying object representation.
65
- *
66
- * This may become undefined across async calls if the weak reference
67
- * is invalidated
68
- */
69
- readonly value: TRepr | undefined;
70
-
71
- /**
72
- * Create a strong reference to the inner value, essentially
73
- * incrementing the ref count.
74
- */
75
- getStrong: () => Erc<TName, TRepr>;
76
- };
77
-
78
- /**
79
- * @deprecated use Emp
80
- */
81
- export type ErcRefType<T> = T extends Erc<infer TName, infer TRepr> ? ErcRef<TName, TRepr> : never;
82
-
83
- /**
84
- * @deprecated use Emp
85
- */
86
- export type ErcTypeConstructor<TName, TRepr> = {
87
- /**
88
- * A marker value for the underlying object type.
89
- *
90
- * This is commonly a string literal or a symbol.
91
- */
92
- marker: TName;
93
-
94
- /**
95
- * The function to free the underlying object.
96
- */
97
- free: (value: TRepr) => void;
98
-
99
- /**
100
- * Given a value, increase the ref count and return the new reference.
101
- * The returned representation should be a different value if double indirection
102
- * is used (each value is a pointer to the smart pointer), or the same value
103
- * if single indirection is used (the value is pointing to the object itself).
104
- */
105
- addRef: (value: TRepr) => TRepr;
106
- };
107
-
108
- /**
109
- * Create a constructor function that serves as the type for an externally ref-counted
110
- * object type. Erc instances can then be created for manually managing memory for
111
- * external objects, typically through FFI.
112
- *
113
- * Since JS is garbage collected and has no way to enforce certain memory management,
114
- * the programmer must ensure that Erc instances are handled correctly!!!
115
- *
116
- * ## Defining Erc type
117
- * ```typescript
118
- * import { makeErcType, type Erc } from "@pistonite/pure/memory";
119
- *
120
- * // 2 functions are required to create an Erc type:
121
- * // free: free the underlying value (essentially decrementing the ref count)
122
- * // addRef: increment the ref count and return the new reference
123
- *
124
- * // here, assume `number` is the JS type used to represent the external object
125
- * // for example, this can be a pointer to a C++ object
126
- * declare function freeFoo(obj: number) => void;
127
- * declare function addRefFoo(obj: number) => number;
128
- *
129
- * // assume another function to create (allocate) the object
130
- * declare function createFoo(): number;
131
- *
132
- * // The recommended way is to create a unique symbol for tracking
133
- * // the external type, you can also use a string literal
134
- * const Foo = Symbol("Foo");
135
- * type Foo = typeof Foo;
136
- *
137
- * // now, we can create the Erc type
138
- * const makeFooErc = makeErcType({
139
- * marker: Foo,
140
- * free: freeFoo,
141
- * addRef: addRefFoo,
142
- * });
143
- *
144
- * // and create Erc instances
145
- * const myFoo: Erc<Foo> = makeFooErc(createFoo());
146
- * ```
147
- *
148
- * ## Using Erc (strong reference)
149
- * Each `Erc` instance is a strong reference, corresponding to some ref-counted
150
- * object externally. Therefore, owner of the `Erc` instance should
151
- * not expose the `Erc` instance to others (for example, returning it from a function),
152
- * since it will lead to memory leak or double free.
153
- * ```typescript
154
- * // create a foo instance externally, and wrap it with Erc
155
- * const myFoo = makeFooErc(createFoo());
156
- *
157
- * // if ownership of myFoo should be returned to external, use `take()`
158
- * // this will make myFoo empty, and doSomethingWithFooExternally should free it
159
- * doSomethingWithFooExternally(myFoo.take());
160
- *
161
- * // you can also free it directly
162
- * foo.free();
163
- * ```
164
- *
165
- * ## Using ErcRef (weak reference)
166
- * Calling `getWeak` on an `Erc` will return a weak reference that has the same
167
- * inner value. The weak reference is safe to be passed around and copied.
168
- * ```typescript
169
- * const myFooWeak = myFoo.getWeak();
170
- * ```
171
- *
172
- * The weak references are tracked by the `Erc` instance.
173
- * In the example above, when `myFoo` is freed, all weak references created by
174
- * `getWeak` will be invalidated. If some other code kept the inner value of
175
- * the weak reference, it will become a dangling pointer.
176
- *
177
- * To avoid this, `getStrong` can be used to create a strong reference if
178
- * the weak reference is still valid, to ensure that the underlying object
179
- * is never freed while still in use
180
- * ```typescript
181
- * const myFooWeak = myFoo.getWeak();
182
- *
183
- * // assume we have some async code that needs to use myFoo
184
- * declare async function doSomethingWithFoo(foo: FooErcRef): Promise<void>;
185
- *
186
- * // Below is BAD!
187
- * await doSomethingWithFoo(myFooWeak);
188
- * // Reason: doSomethingWithFoo is async, so it's possible that
189
- * // myFooWeak is invalidated when it's still needed. If the implementation
190
- * // does not check for that, it could be deferencing a dangling pointer
191
- * // (of course, it could actually be fine depending on the implementation of doSomethingWithFoo)
192
- *
193
- * // Recommendation is to use strong reference for async operations
194
- * const myFooStrong = myFooWeak.getStrong();
195
- * await doSomethingWithFoo(myFooStrong.getWeak()); // will never be freed while awaiting
196
- * // now we free
197
- * myFooStrong.free();
198
- *
199
- * ```
200
- *
201
- * ## Assigning to Erc
202
- * Each `Erc` instance should only ever have one external reference. So you should not
203
- * assign to an `Erc` variable directly:
204
- * ```typescript
205
- * // DO NOT DO THIS
206
- * let myFoo = makeFooErc(createFoo());
207
- * myFoo = makeFooErc(createFoo()); // previous Erc is overriden without proper clean up
208
- * ```
209
- *
210
- * If you want to attach a new value to an existing `Erc`, use the `assign` method:
211
- * ```typescript
212
- * const myFoo = makeFooErc(createFoo());
213
- * myFoo.assign(createFoo()); // previous Erc is freed, and the new one is assigned
214
- * myFoo.free(); // new one is freed
215
- * ```
216
- * The example above does not cause leaks, since the previous Erc is freed
217
- *
218
- * However, if you call assign with the value of another `Erc`, it will cause memory
219
- * issues:
220
- * ```typescript
221
- * // DO NOT DO THIS
222
- * const myFoo1 = makeFooErc(createFoo());
223
- * const myFoo2 = makeFooErc(createFoo());
224
- * myFoo1.assign(myFoo2.value); // myFoo1 is freed, and myFoo2 is assigned
225
- * // BAD: now both myFoo1 and myFoo2 references the same object, but the ref count is 1
226
- * myFoo1.free(); // no issue here, object is freed, but myFoo2 now holds a dangling pointer
227
- * myFoo2.free(); // double free!
228
- *
229
- * // The correct way to do this is to use `take`:
230
- * const myFoo1 = makeFooErc(createFoo());
231
- * const myFoo2 = makeFooErc(createFoo());
232
- * myFoo1.assign(myFoo2.take()); // myFoo1 is freed, and myFoo2 is assigned, myFoo2 is empty
233
- * myFoo1.free(); // no issue here, object is freed
234
- * // myFoo2 is empty, so calling free() has no effect
235
- * ```
236
- *
237
- * Assign also works if both `Erc` are 2 references of the same object:
238
- * ```typescript
239
- * const myFoo1 = makeFooErc(createFoo()); // ref count is 1
240
- * const myFoo2 = myFoo1.getStrong(); // ref count is 2
241
- * myFoo1.assign(myFoo2.take()); // frees old value, ref count is 1
242
- *
243
- * // This also works:
244
- * const myFoo1 = makeFooErc(createFoo()); // ref count is 1
245
- * myFoo1.assign(myFoo1.take()); // take() makes myFoo1 empty, so assign() doesn't free it
246
- *
247
- * // DO NOT DO THIS:
248
- * myFoo1.assign(myFoo1.value); // this will free the value since ref count is 0, and result in a dangling pointer
249
- * ```
250
- *
251
- * @deprecated use Emp
252
- */
253
- export const makeErcType = <TName, TRepr>({
254
- marker,
255
- free,
256
- addRef,
257
- }: ErcTypeConstructor<TName, TRepr>): ((value: TRepr | undefined) => Erc<TName, TRepr>) => {
258
- const createStrongRef = (value: TRepr | undefined): Erc<TName, TRepr> => {
259
- let weakRef: (ErcRef<TName, TRepr> & { invalidate: () => void }) | undefined = undefined;
260
- const invalidateWeakRef = () => {
261
- if (!weakRef) {
262
- return;
263
- }
264
- const oldWeakRef = weakRef;
265
- weakRef = undefined;
266
- oldWeakRef.invalidate();
267
- };
268
- const createWeakRef = (initialValue: TRepr | undefined) => {
269
- const weak = {
270
- type: marker,
271
- value: initialValue,
272
- invalidate: () => {
273
- weak.value = undefined;
274
- },
275
- getStrong: () => {
276
- if (weak.value === undefined) {
277
- return createStrongRef(undefined);
278
- }
279
- return createStrongRef(addRef(weak.value));
280
- },
281
- };
282
- return weak;
283
- };
284
- const erc = {
285
- type: marker,
286
- value,
287
- free: () => {
288
- if (erc.value !== undefined) {
289
- invalidateWeakRef();
290
- free(erc.value);
291
- erc.value = undefined;
292
- }
293
- },
294
- assign: (newValue: TRepr | undefined) => {
295
- erc.free();
296
- erc.value = newValue;
297
- },
298
- take: () => {
299
- invalidateWeakRef();
300
- const oldValue = erc.value;
301
- erc.value = undefined;
302
- return oldValue;
303
- },
304
- getWeak: () => {
305
- if (!weakRef) {
306
- weakRef = createWeakRef(erc.value);
307
- }
308
- return weakRef;
309
- },
310
- getStrong: () => {
311
- if (erc.value === undefined) {
312
- return createStrongRef(undefined);
313
- }
314
- return createStrongRef(addRef(erc.value));
315
- },
316
- };
317
- return erc;
318
- };
319
- return createStrongRef;
320
- };
package/src/pref/dark.ts DELETED
@@ -1,151 +0,0 @@
1
- import { persist } from "../memory/persist.ts";
2
- import { injectStyle } from "./inject_style.ts";
3
-
4
- const dark = persist({
5
- initial: false,
6
- key: "Pure.Dark",
7
- storage: localStorage,
8
- serialize: (value) => (value ? "1" : ""),
9
- deserialize: (value) => !!value,
10
- });
11
-
12
- /**
13
- * Returns if dark mode is prefered in the browser environment
14
- *
15
- * If `window.matchMedia` is not available, it will return `false`
16
- */
17
- export const prefersDarkMode = (): boolean => {
18
- return !!globalThis.matchMedia?.("(prefers-color-scheme: dark)").matches;
19
- };
20
-
21
- /** Value for the `color-scheme` CSS property */
22
- export type ColorScheme = "light" | "dark";
23
- /** Option for initializing dark mode */
24
- export type DarkOptions = {
25
- /**
26
- * Initial value for dark mode
27
- *
28
- * If not set, it will default to calling `prefersDarkMode()`.
29
- *
30
- * If `persist` is `true`, it will also check the value from localStorage
31
- */
32
- initial?: boolean;
33
- /** Persist the dark mode preference to localStorage */
34
- persist?: boolean;
35
- /**
36
- * The selector to set `color-scheme` property
37
- *
38
- * Defaults to `:root`. If set to empty string, CSS will not be updated
39
- */
40
- selector?: string;
41
- };
42
-
43
- /**
44
- * Init Dark mode wrappers
45
- *
46
- * ## Detect user preference
47
- * User preference is detected with `matchMedia` API, if available.
48
- * ```typescript
49
- * import { prefersDarkMode } from "@pistonite/pure/dark";
50
- *
51
- * console.log(prefersDarkMode());
52
- * ```
53
- *
54
- * ## Global dark mode state
55
- * `initDark` initializes the dark mode state.
56
- * ```typescript
57
- * import { initDark, isDark, setDark, addDarkSubscriber } from "@pistonite/pure/dark";
58
- *
59
- * initDark();
60
- * console.log(isDark());
61
- *
62
- * addDarkSubscriber((dark) => { console.log("Dark mode changed: ", dark); });
63
- * setDark(true); // will trigger the subscriber
64
- * ```
65
- *
66
- * ## Use with React
67
- * A React hook is provided in the [`pure-react`](https://jsr.io/@pistonite/pure-react/doc/pref) package
68
- * to get the dark mode state from React components.
69
- *
70
- * Use `setDark` to change the dark mode state from React compoenents like you would from anywhere else.
71
- *
72
- * ## Persisting to localStorage
73
- * You can persist the dark mode preference to by passing `persist: true` to `initDark`.
74
- * This will make `initDark` also load the preference from localStorage.
75
- * ```typescript
76
- * import { initDark } from "@pistonite/pure/dark";
77
- *
78
- * initDark({ persist: true });
79
- * ```
80
- *
81
- * ## Setting `color-scheme` CSS property
82
- * The `color-scheme` property handles dark mode for native components like buttons
83
- * and scrollbars. By default, `initDark` will handle setting this property for the `:root` selector.
84
- * You can override this by passing a `selector` option.
85
- * ```typescript
86
- * import { initDark } from "@pistonite/pure/dark";
87
- *
88
- * // will set `.my-app { color-scheme: dark }`
89
- * initDark({ selector: ".my-app" });
90
- * ```
91
- */
92
- export const initDark = (options: DarkOptions = {}): void => {
93
- const _dark = options.initial || prefersDarkMode();
94
-
95
- const selector = options.selector ?? ":root";
96
- if (selector) {
97
- // notify immediately to update the style initially
98
- addDarkSubscriber((dark: boolean) => {
99
- updateStyle(dark, selector);
100
- }, true /* notify */);
101
- }
102
-
103
- if (options.persist) {
104
- dark.init(_dark);
105
- } else {
106
- dark.disable();
107
- dark.set(_dark);
108
- }
109
- };
110
-
111
- /**
112
- * Clears the persisted dark mode preference
113
- *
114
- * If you are doing this, you should probably call `setDark`
115
- * with `prefersDarkMode()` or some initial value immediately before this,
116
- * so the current dark mode is set to user's preferred mode.
117
- *
118
- * Note if `persist` is `true` when initializing,
119
- * subsequence `setDark` calls will still persist the value.
120
- */
121
- export const clearPersistedDarkPerference = (): void => {
122
- dark.clear();
123
- };
124
-
125
- /**
126
- * Gets the current value of dark mode
127
- */
128
- export const isDark = (): boolean => dark.get();
129
-
130
- /**
131
- * Set the value of dark mode
132
- */
133
- export const setDark = (value: boolean): void => {
134
- dark.set(value);
135
- };
136
- /**
137
- * Add a subscriber to dark mode changes and return a function to remove the subscriber
138
- *
139
- * If `notifyImmediately` is `true`, the subscriber will be called immediately with the current value
140
- */
141
- export const addDarkSubscriber = (
142
- subscriber: (dark: boolean) => void,
143
- notifyImmediately?: boolean,
144
- ): (() => void) => {
145
- return dark.subscribe(subscriber, notifyImmediately);
146
- };
147
-
148
- const updateStyle = (dark: boolean, selector: string) => {
149
- const text = `${selector} { color-scheme: ${dark ? "dark" : "light"}; }`;
150
- injectStyle("pure-pref-dark", text);
151
- };
@@ -1,118 +0,0 @@
1
- import { ilog } from "../log/internal.ts";
2
- import { cell } from "../memory";
3
-
4
- let cachedIsMobile: boolean | undefined = undefined;
5
-
6
- /** Check if the current UserAgent is a mobile device */
7
- export const isMobile = (): boolean => {
8
- // just very primitive UA parsing for now,
9
- // we don't need to take another dependency just to detect
10
- // a few platforms
11
- if (cachedIsMobile === undefined) {
12
- const ua = navigator?.userAgent || "";
13
- if (ua.match(/(Windows NT|Macintosh|)/i)) {
14
- cachedIsMobile = false;
15
- } else if (ua.match(/(Mobil|iPhone|Android|iPod|iPad)/)) {
16
- cachedIsMobile = true;
17
- } else if (ua.includes("Linux")) {
18
- cachedIsMobile = false;
19
- } else {
20
- ilog.warn("unable to determine device type, assuming desktop");
21
- cachedIsMobile = true;
22
- }
23
- }
24
- return cachedIsMobile;
25
- };
26
-
27
- // stores current display mode
28
- const displayMode = cell({ initial: "" });
29
-
30
- /**
31
- * Options for display mode detection
32
- *
33
- * See {@link initDisplayMode}
34
- */
35
- export type DisplayModeOptions<T extends string> = {
36
- /**
37
- * Set the initial value, if the platform doesn't support detecting
38
- * the display mode. `detect()` will be used instead if supported
39
- */
40
- initial?: T;
41
- /**
42
- * Function to determine the display mode based on viewport width and height,
43
- * and if the device is mobile
44
- */
45
- detect: (width: number, height: number, isMobile: boolean) => T;
46
- };
47
-
48
- /**
49
- * Initialize display mode detection for the app.
50
- *
51
- * The display mode may be based on the viewport dimensions
52
- * and if the device is mobile. Also note that you can use {@link isMobile}
53
- * without the display mode framework.
54
- *
55
- * The display modes are strings that should be passed as a type parameter
56
- * to {@link initDisplayMode}. You can create an alias in your code for
57
- * getting the typed version of {@link addDisplayModeSubscriber}, {@link getDisplayMode},
58
- * and {@link useDisplayMode} from `pure-react`.
59
- *
60
- * ```typescript
61
- * import {
62
- * addDisplayModeSubscriber as pureAddDisplayModeSubscriber,
63
- * getDisplayMode as pureGetDisplayMode,
64
- * } from "@pistonite/pure/pref";
65
- * import { useDisplayMode as pureUseDisplayMode } from "@pistonite/pure-react";
66
- *
67
- * export const MyDisplayModes = ["mode1", "mode2"] as const;
68
- * export type MyDisplayMode = (typeof MyDisplayModes)[number];
69
- *
70
- * export const addDisplayModeSubscriber = pureAddDisplayModeSubscriber<MyDisplayMode>;
71
- * export const getDisplayMode = pureGetDisplayMode<MyDisplayMode>;
72
- * export const useDisplayMode = pureUseDisplayMode<MyDisplayMode>;
73
- * ```
74
- *
75
- * Note that this is not necessary in some simple use cases. For example,
76
- * adjusting styles based on the viewport width can be done with CSS:
77
- * ```css
78
- * @media screen and (max-width: 800px) {
79
- * /* styles for narrow mode * /
80
- * }
81
- * ```
82
- *
83
- * Use this only if the display mode needs to be detected programmatically.
84
- */
85
- export const initDisplayMode = <T extends string>(options: DisplayModeOptions<T>) => {
86
- const detectCallback = () => {
87
- const mode = options.detect(window.innerWidth, window.innerHeight, isMobile());
88
- displayMode.set(mode);
89
- };
90
- if (
91
- window &&
92
- window.addEventListener &&
93
- window.innerWidth !== undefined &&
94
- window.innerHeight !== undefined
95
- ) {
96
- window.addEventListener("resize", detectCallback);
97
- detectCallback();
98
- } else if (options.initial !== undefined) {
99
- displayMode.set(options.initial);
100
- } else {
101
- ilog.warn(
102
- "display mode cannot be initialized, since detection is not supported and initial is not set",
103
- );
104
- }
105
- };
106
-
107
- /** Subscribe to display mode changes */
108
- export const addDisplayModeSubscriber = <T extends string>(
109
- subscriber: (mode: T) => void,
110
- notifyImmediately?: boolean,
111
- ) => {
112
- return displayMode.subscribe(subscriber as (x: string) => void, notifyImmediately);
113
- };
114
-
115
- /** Get the current display mode */
116
- export const getDisplayMode = <T extends string>(): T => {
117
- return displayMode.get() as T;
118
- };
package/src/pref/index.ts DELETED
@@ -1,13 +0,0 @@
1
- /**
2
- * # pure/pref
3
- * Preference utilities (things like locale and theme).
4
- *
5
- * These deal with raw CSS and DOM API, and is probably not
6
- * very useful outside of browser environment.
7
- *
8
- * @module
9
- */
10
- export * from "./dark.ts";
11
- export * from "./inject_style.ts";
12
- export * from "./locale.ts";
13
- export * from "./device.ts";
@@ -1,22 +0,0 @@
1
- /**
2
- * Inject a css string into a style tag identified by the id
3
- *
4
- * Will remove the old style tag(s) if exist
5
- */
6
- export function injectStyle(id: string, style: string) {
7
- const styleTags = document.querySelectorAll(`style[data-inject="${id}"]`);
8
- if (styleTags.length !== 1) {
9
- const styleTag = document.createElement("style");
10
- styleTag.setAttribute("data-inject", id);
11
- styleTag.innerText = style;
12
- document.head.appendChild(styleTag);
13
- setTimeout(() => {
14
- styleTags.forEach((tag) => tag.remove());
15
- }, 0);
16
- } else {
17
- const e = styleTags[0] as HTMLStyleElement;
18
- if (e.innerText !== style) {
19
- e.innerText = style;
20
- }
21
- }
22
- }