@streamscloud/kit 0.59.0 → 0.61.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.
- package/dist/core/i18n/index.d.ts +1 -1
- package/dist/core/i18n/index.js +1 -1
- package/dist/core/i18n/resolve-plural-form.d.ts +23 -0
- package/dist/core/i18n/resolve-plural-form.js +41 -0
- package/dist/ui/cropper/img-cropper/cropperjs-elements.d.ts +9 -7
- package/dist/ui/dynamic-component/cmp.dynamic-component.svelte +0 -14
- package/dist/ui/dynamic-component/cmp.dynamic-component.svelte.d.ts +0 -14
- package/dist/ui/grid-card/fields/cmp.grid-card-progress-field.svelte +1 -2
- package/dist/ui/grid-card/fields/cmp.grid-card-progress-field.svelte.d.ts +1 -4
- package/dist/ui/popover/cmp.hover-popover.svelte +0 -9
- package/dist/ui/popover/cmp.hover-popover.svelte.d.ts +0 -9
- package/dist/ui/popover/cmp.popover.svelte +1 -9
- package/dist/ui/popover/cmp.popover.svelte.d.ts +1 -9
- package/package.json +23 -23
- package/dist/core/i18n/plural.d.ts +0 -14
- package/dist/core/i18n/plural.js +0 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { resolvePluralForm } from './resolve-plural-form';
|
package/dist/core/i18n/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { resolvePluralForm } from './resolve-plural-form';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type ResolvePluralFormOptions = {
|
|
2
|
+
count: number;
|
|
3
|
+
candidates: [string, ...string[]];
|
|
4
|
+
locale: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Picks the plural form matching `count` for `locale`.
|
|
8
|
+
*
|
|
9
|
+
* @param count - The number to pluralize
|
|
10
|
+
* @param candidates - One string per plural category `locale` distinguishes, in canonical CLDR order
|
|
11
|
+
* (zero, one, two, few, many, other) filtered to that locale's categories — e.g. 2 entries for 'en'
|
|
12
|
+
* (one, other), 4 for 'ru' (one, few, many, other). The caller (or its translation catalog) owns
|
|
13
|
+
* supplying the right length and order for the given locale. In dev, a length mismatch against
|
|
14
|
+
* `locale`'s actual category count throws instead of silently resolving the wrong form.
|
|
15
|
+
* @param locale - BCP 47 locale used to resolve the matching category via `Intl.PluralRules`.
|
|
16
|
+
* Invalid locale tags silently fall back to the runtime default — validate the locale upstream.
|
|
17
|
+
* @returns The matching candidate with # replaced by count
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* resolvePluralForm({ count: 1, candidates: ['# item', '# items'], locale: 'en' }) // "1 item"
|
|
21
|
+
* resolvePluralForm({ count: 5, candidates: ['# item', '# items'], locale: 'en' }) // "5 items"
|
|
22
|
+
*/
|
|
23
|
+
export declare const resolvePluralForm: ({ count, candidates, locale }: ResolvePluralFormOptions) => string;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Picks the plural form matching `count` for `locale`.
|
|
3
|
+
*
|
|
4
|
+
* @param count - The number to pluralize
|
|
5
|
+
* @param candidates - One string per plural category `locale` distinguishes, in canonical CLDR order
|
|
6
|
+
* (zero, one, two, few, many, other) filtered to that locale's categories — e.g. 2 entries for 'en'
|
|
7
|
+
* (one, other), 4 for 'ru' (one, few, many, other). The caller (or its translation catalog) owns
|
|
8
|
+
* supplying the right length and order for the given locale. In dev, a length mismatch against
|
|
9
|
+
* `locale`'s actual category count throws instead of silently resolving the wrong form.
|
|
10
|
+
* @param locale - BCP 47 locale used to resolve the matching category via `Intl.PluralRules`.
|
|
11
|
+
* Invalid locale tags silently fall back to the runtime default — validate the locale upstream.
|
|
12
|
+
* @returns The matching candidate with # replaced by count
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* resolvePluralForm({ count: 1, candidates: ['# item', '# items'], locale: 'en' }) // "1 item"
|
|
16
|
+
* resolvePluralForm({ count: 5, candidates: ['# item', '# items'], locale: 'en' }) // "5 items"
|
|
17
|
+
*/
|
|
18
|
+
export const resolvePluralForm = ({ count, candidates, locale }) => {
|
|
19
|
+
const { index, categoriesLength } = indexerFor(locale);
|
|
20
|
+
if (import.meta.env?.DEV && candidates.length !== categoriesLength) {
|
|
21
|
+
throw new Error(`resolvePluralForm(): locale "${locale}" needs ${categoriesLength} candidate(s), got ${JSON.stringify(candidates)}.`);
|
|
22
|
+
}
|
|
23
|
+
const template = candidates[index(count)] ?? candidates[candidates.length - 1];
|
|
24
|
+
return template.replace(/#/g, String(count));
|
|
25
|
+
};
|
|
26
|
+
const PLURAL_CATEGORY_ORDER = ['zero', 'one', 'two', 'few', 'many', 'other'];
|
|
27
|
+
const indexers = new Map();
|
|
28
|
+
const indexerFor = (locale) => {
|
|
29
|
+
const cached = indexers.get(locale);
|
|
30
|
+
if (cached) {
|
|
31
|
+
return cached;
|
|
32
|
+
}
|
|
33
|
+
const rules = new Intl.PluralRules(locale);
|
|
34
|
+
const categories = rules
|
|
35
|
+
.resolvedOptions()
|
|
36
|
+
.pluralCategories.slice()
|
|
37
|
+
.sort((a, b) => PLURAL_CATEGORY_ORDER.indexOf(a) - PLURAL_CATEGORY_ORDER.indexOf(b));
|
|
38
|
+
const indexer = { index: (count) => categories.indexOf(rules.select(count)), categoriesLength: categories.length };
|
|
39
|
+
indexers.set(locale, indexer);
|
|
40
|
+
return indexer;
|
|
41
|
+
};
|
|
@@ -9,15 +9,17 @@ type CamelToKebab<S extends string> = S extends `${infer F}${infer R}`
|
|
|
9
9
|
: S;
|
|
10
10
|
|
|
11
11
|
type CropperElementProps<T extends HTMLElement> = {
|
|
12
|
-
[
|
|
13
|
-
|
|
14
|
-
: K extends `$${string}`
|
|
12
|
+
[
|
|
13
|
+
K in keyof T as K extends keyof HTMLElement
|
|
15
14
|
? never
|
|
16
|
-
:
|
|
15
|
+
: K extends `$${string}`
|
|
17
16
|
? never
|
|
18
|
-
: K extends
|
|
19
|
-
?
|
|
20
|
-
:
|
|
17
|
+
: T[K] extends (...args: never[]) => unknown
|
|
18
|
+
? never
|
|
19
|
+
: K extends string
|
|
20
|
+
? CamelToKebab<K>
|
|
21
|
+
: never
|
|
22
|
+
]?: (T[K] extends boolean ? boolean : T[K] extends number ? number | string : string) | null;
|
|
21
23
|
} & import('svelte/elements').HTMLAttributes<HTMLElement>;
|
|
22
24
|
|
|
23
25
|
declare namespace svelteHTML {
|
|
@@ -12,19 +12,5 @@ Use when the component to render is decided at runtime (e.g. dispatched by id, f
|
|
|
12
12
|
renders many heterogeneous nodes). `DynamicComponentModel` keeps `props` reactive — calling
|
|
13
13
|
`model.updateProps(...)` updates the rendered component without re-mounting.
|
|
14
14
|
|
|
15
|
-
```svelte
|
|
16
|
-
<script lang="ts">
|
|
17
|
-
import { DynamicComponent, DynamicComponentModel } from '@streamscloud/kit/dynamic-component';
|
|
18
|
-
import { Button } from '@streamscloud/kit/button';
|
|
19
|
-
|
|
20
|
-
const model = new DynamicComponentModel({
|
|
21
|
-
component: Button,
|
|
22
|
-
props: { type: 'button', children: () => 'Click' }
|
|
23
|
-
});
|
|
24
|
-
</script>
|
|
25
|
-
|
|
26
|
-
<DynamicComponent {model} />
|
|
27
|
-
```
|
|
28
|
-
|
|
29
15
|
This component has no styles or visual surface of its own.
|
|
30
16
|
-->
|
|
@@ -10,20 +10,6 @@ type Props = {
|
|
|
10
10
|
* renders many heterogeneous nodes). `DynamicComponentModel` keeps `props` reactive — calling
|
|
11
11
|
* `model.updateProps(...)` updates the rendered component without re-mounting.
|
|
12
12
|
*
|
|
13
|
-
* ```svelte
|
|
14
|
-
* <script lang="ts">
|
|
15
|
-
* import { DynamicComponent, DynamicComponentModel } from '@streamscloud/kit/dynamic-component';
|
|
16
|
-
* import { Button } from '@streamscloud/kit/button';
|
|
17
|
-
*
|
|
18
|
-
* const model = new DynamicComponentModel({
|
|
19
|
-
* component: Button,
|
|
20
|
-
* props: { type: 'button', children: () => 'Click' }
|
|
21
|
-
* });
|
|
22
|
-
* </script>
|
|
23
|
-
*
|
|
24
|
-
* <DynamicComponent {model} />
|
|
25
|
-
* ```
|
|
26
|
-
*
|
|
27
13
|
* This component has no styles or visual surface of its own.
|
|
28
14
|
*/
|
|
29
15
|
declare const Cmp: import("svelte").Component<Props, {}, "">;
|
|
@@ -9,6 +9,5 @@ const { label, stage, stages } = $props();
|
|
|
9
9
|
|
|
10
10
|
<!--
|
|
11
11
|
@component
|
|
12
|
-
Grid-card field pairing a field label with a multi-stage `ProgressBar`. See `ProgressBar`
|
|
13
|
-
(`@streamscloud/kit/ui/progress-bar`) for the bar's own CSS Custom Properties.
|
|
12
|
+
Grid-card field pairing a field label with a multi-stage `ProgressBar`. See `ProgressBar` for the bar's own CSS Custom Properties.
|
|
14
13
|
-->
|
|
@@ -9,10 +9,7 @@ type Props = {
|
|
|
9
9
|
*/
|
|
10
10
|
stages: ProgressBarStage[];
|
|
11
11
|
};
|
|
12
|
-
/**
|
|
13
|
-
* Grid-card field pairing a field label with a multi-stage `ProgressBar`. See `ProgressBar`
|
|
14
|
-
* (`@streamscloud/kit/ui/progress-bar`) for the bar's own CSS Custom Properties.
|
|
15
|
-
*/
|
|
12
|
+
/** Grid-card field pairing a field label with a multi-stage `ProgressBar`. See `ProgressBar` for the bar's own CSS Custom Properties. */
|
|
16
13
|
declare const Cmp: import("svelte").Component<Props, {}, "">;
|
|
17
14
|
type Cmp = ReturnType<typeof Cmp>;
|
|
18
15
|
export default Cmp;
|
|
@@ -48,15 +48,6 @@ to content stays "inside" the hover zone (no close fires). The `closeDelay` cove
|
|
|
48
48
|
small visual gap between trigger and content.
|
|
49
49
|
|
|
50
50
|
`bind:this` on HoverPopover forwards `open() / close() / toggle()` from the inner Popover.
|
|
51
|
-
|
|
52
|
-
```svelte
|
|
53
|
-
import { HoverPopover, PopoverItem } from '@streamscloud/kit/ui/popover';
|
|
54
|
-
|
|
55
|
-
<HoverPopover>
|
|
56
|
-
{#snippet trigger()}<Button type="presentational">Hover me</Button>{/snippet}
|
|
57
|
-
<PopoverItem>Action</PopoverItem>
|
|
58
|
-
</HoverPopover>
|
|
59
|
-
```
|
|
60
51
|
-->
|
|
61
52
|
|
|
62
53
|
<style>.hover-popover {
|
|
@@ -33,15 +33,6 @@ type Props = {
|
|
|
33
33
|
* small visual gap between trigger and content.
|
|
34
34
|
*
|
|
35
35
|
* `bind:this` on HoverPopover forwards `open() / close() / toggle()` from the inner Popover.
|
|
36
|
-
*
|
|
37
|
-
* ```svelte
|
|
38
|
-
* import { HoverPopover, PopoverItem } from '@streamscloud/kit/ui/popover';
|
|
39
|
-
*
|
|
40
|
-
* <HoverPopover>
|
|
41
|
-
* {#snippet trigger()}<Button type="presentational">Hover me</Button>{/snippet}
|
|
42
|
-
* <PopoverItem>Action</PopoverItem>
|
|
43
|
-
* </HoverPopover>
|
|
44
|
-
* ```
|
|
45
36
|
*/
|
|
46
37
|
declare const Cmp: import("svelte").Component<Props, {
|
|
47
38
|
/** Imperative API — bind:this on HoverPopover to access. */ open: () => void;
|
|
@@ -226,15 +226,7 @@ the same state can be reached by keyboard through another control (as in `UrlInp
|
|
|
226
226
|
protocol into the field does what the picker does). Never reach for it just to shorten a tab sequence.
|
|
227
227
|
|
|
228
228
|
Imperative control via `bind:this` — the component exports `open()`, `close()`, `toggle()`
|
|
229
|
-
methods
|
|
230
|
-
|
|
231
|
-
```svelte
|
|
232
|
-
import { Popover, type PopoverInstance } from '@streamscloud/kit/ui/popover';
|
|
233
|
-
let dd: PopoverInstance | undefined = $state.raw(undefined);
|
|
234
|
-
|
|
235
|
-
<Popover bind:this={dd}>...</Popover>
|
|
236
|
-
<button onclick={() => dd?.open()}>Open externally</button>
|
|
237
|
-
```
|
|
229
|
+
methods; type the ref with the exported `PopoverInstance` type.
|
|
238
230
|
|
|
239
231
|
With `panel` on, content sizes to `max-content` and, above the `min-width` floor, never exceeds the room Floating UI measures around the trigger: the `size()` middleware feeds the space left after
|
|
240
232
|
`flip` / `shift` into the max-width / max-height defaults. So the panel always has a definite width — which is what makes a consumer's own
|
|
@@ -51,15 +51,7 @@ type Props = {
|
|
|
51
51
|
* protocol into the field does what the picker does). Never reach for it just to shorten a tab sequence.
|
|
52
52
|
*
|
|
53
53
|
* Imperative control via `bind:this` — the component exports `open()`, `close()`, `toggle()`
|
|
54
|
-
* methods
|
|
55
|
-
*
|
|
56
|
-
* ```svelte
|
|
57
|
-
* import { Popover, type PopoverInstance } from '@streamscloud/kit/ui/popover';
|
|
58
|
-
* let dd: PopoverInstance | undefined = $state.raw(undefined);
|
|
59
|
-
*
|
|
60
|
-
* <Popover bind:this={dd}>...</Popover>
|
|
61
|
-
* <button onclick={() => dd?.open()}>Open externally</button>
|
|
62
|
-
* ```
|
|
54
|
+
* methods; type the ref with the exported `PopoverInstance` type.
|
|
63
55
|
*
|
|
64
56
|
* With `panel` on, content sizes to `max-content` and, above the `min-width` floor, never exceeds the room Floating UI measures around the trigger: the `size()` middleware feeds the space left after
|
|
65
57
|
* `flip` / `shift` into the max-width / max-height defaults. So the panel always has a definite width — which is what makes a consumer's own
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamscloud/kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.61.0",
|
|
4
4
|
"author": "StreamsCloud",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -482,11 +482,11 @@
|
|
|
482
482
|
},
|
|
483
483
|
"peerDependencies": {
|
|
484
484
|
"@floating-ui/dom": "^1.7.6",
|
|
485
|
-
"@fluentui/svg-icons": "^1.1.
|
|
485
|
+
"@fluentui/svg-icons": "^1.1.341",
|
|
486
486
|
"@fontsource/inter": "^5.2.8",
|
|
487
487
|
"@fontsource/jetbrains-mono": "^5.2.8",
|
|
488
488
|
"@fontsource/source-sans-pro": "^5.2.5",
|
|
489
|
-
"@urql/core": "^
|
|
489
|
+
"@urql/core": "^6.0.1",
|
|
490
490
|
"cleave-zen": "^0.0.17",
|
|
491
491
|
"colord": "^2.9.3",
|
|
492
492
|
"cropperjs": "^2.1.1",
|
|
@@ -498,7 +498,7 @@
|
|
|
498
498
|
"nanoid": "^5.1.11",
|
|
499
499
|
"p-limit": "^7.3.0",
|
|
500
500
|
"rfdc": "^1.4.1",
|
|
501
|
-
"svelte": "^5.
|
|
501
|
+
"svelte": "^5.57.0",
|
|
502
502
|
"svelte-awesome-color-picker": "^4.1.2",
|
|
503
503
|
"svelte-dnd-action": "^0.9.69",
|
|
504
504
|
"wheel-gestures": "^2.2.48",
|
|
@@ -507,50 +507,50 @@
|
|
|
507
507
|
"devDependencies": {
|
|
508
508
|
"@eslint/js": "^10.0.1",
|
|
509
509
|
"@floating-ui/dom": "^1.7.6",
|
|
510
|
-
"@fluentui/svg-icons": "^1.1.
|
|
510
|
+
"@fluentui/svg-icons": "^1.1.341",
|
|
511
511
|
"@fontsource/inter": "^5.2.8",
|
|
512
512
|
"@fontsource/jetbrains-mono": "^5.2.8",
|
|
513
513
|
"@fontsource/source-sans-pro": "^5.2.5",
|
|
514
|
-
"@sveltejs/package": "^2.5.
|
|
515
|
-
"@sveltejs/vite-plugin-svelte": "^7.
|
|
514
|
+
"@sveltejs/package": "^2.5.8",
|
|
515
|
+
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
516
516
|
"@tsconfig/svelte": "^5.0.8",
|
|
517
|
-
"@types/node": "^
|
|
517
|
+
"@types/node": "^26.6.1",
|
|
518
518
|
"@urql/core": "^6.0.1",
|
|
519
|
-
"autoprefixer": "^10.
|
|
519
|
+
"autoprefixer": "^10.6.1",
|
|
520
520
|
"cleave-zen": "^0.0.17",
|
|
521
521
|
"colord": "^2.9.3",
|
|
522
522
|
"cropperjs": "^2.1.1",
|
|
523
523
|
"dequal": "^2.0.3",
|
|
524
524
|
"dompurify": "^3.4.5",
|
|
525
|
-
"eslint": "^10.
|
|
525
|
+
"eslint": "^10.10.0",
|
|
526
526
|
"eslint-config-prettier": "^10.1.8",
|
|
527
527
|
"eslint-formatter-codeframe": "^7.32.2",
|
|
528
528
|
"eslint-formatter-visualstudio": "^9.0.1",
|
|
529
|
-
"eslint-plugin-import-x": "^4.
|
|
530
|
-
"eslint-plugin-jsonc": "^3.
|
|
529
|
+
"eslint-plugin-import-x": "^4.17.1",
|
|
530
|
+
"eslint-plugin-jsonc": "^3.4.2",
|
|
531
531
|
"eslint-plugin-only-warn": "^1.2.1",
|
|
532
532
|
"eslint-plugin-promise": "^7.3.0",
|
|
533
|
-
"eslint-plugin-svelte": "^3.
|
|
533
|
+
"eslint-plugin-svelte": "^3.23.0",
|
|
534
534
|
"eslint-plugin-unused-imports": "^4.4.1",
|
|
535
535
|
"fuse.js": "^7.3.0",
|
|
536
|
-
"globals": "^17.
|
|
536
|
+
"globals": "^17.12.0",
|
|
537
537
|
"hugerte": "^1.0.10",
|
|
538
538
|
"mime": "^4.1.0",
|
|
539
539
|
"nanoid": "^5.1.11",
|
|
540
540
|
"p-limit": "^7.3.0",
|
|
541
|
-
"prettier": "^3.
|
|
542
|
-
"prettier-plugin-svelte": "^4.1.
|
|
543
|
-
"publint": "^0.3.
|
|
541
|
+
"prettier": "^3.9.7",
|
|
542
|
+
"prettier-plugin-svelte": "^4.1.1",
|
|
543
|
+
"publint": "^0.3.24",
|
|
544
544
|
"rfdc": "^1.4.1",
|
|
545
|
-
"sass": "^1.
|
|
546
|
-
"svelte": "^5.
|
|
545
|
+
"sass": "^1.104.1",
|
|
546
|
+
"svelte": "^5.57.0",
|
|
547
547
|
"svelte-awesome-color-picker": "^4.1.2",
|
|
548
|
-
"svelte-check": "^4.
|
|
548
|
+
"svelte-check": "^4.7.6",
|
|
549
549
|
"svelte-dnd-action": "^0.9.69",
|
|
550
|
-
"svelte-preprocess": "^6.0.
|
|
550
|
+
"svelte-preprocess": "^6.0.5",
|
|
551
551
|
"typescript": "^6.0.3",
|
|
552
|
-
"typescript-eslint": "^8.
|
|
553
|
-
"vite": "^8.0
|
|
552
|
+
"typescript-eslint": "^8.70.0",
|
|
553
|
+
"vite": "^8.3.0",
|
|
554
554
|
"vite-tsconfig-paths": "^6.1.1",
|
|
555
555
|
"wheel-gestures": "^2.2.48",
|
|
556
556
|
"yup": "^1.7.1"
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plural function for wuchale i18n.
|
|
3
|
-
* Wuchale extracts the candidates array and compiles locale-specific plural rules.
|
|
4
|
-
*
|
|
5
|
-
* @param count - The number to pluralize
|
|
6
|
-
* @param candidates - Array of plural forms, e.g., ['One item', '# items']
|
|
7
|
-
* @param rule - Optional plural rule function (injected by wuchale at compile time)
|
|
8
|
-
* @returns The appropriate plural form with # replaced by count
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* plural(1, ['# item', '# items']) // "1 item"
|
|
12
|
-
* plural(5, ['# item', '# items']) // "5 items"
|
|
13
|
-
*/
|
|
14
|
-
export declare const plural: (count: number, candidates: string[], rule?: (n: number) => number) => string;
|
package/dist/core/i18n/plural.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Plural function for wuchale i18n.
|
|
3
|
-
* Wuchale extracts the candidates array and compiles locale-specific plural rules.
|
|
4
|
-
*
|
|
5
|
-
* @param count - The number to pluralize
|
|
6
|
-
* @param candidates - Array of plural forms, e.g., ['One item', '# items']
|
|
7
|
-
* @param rule - Optional plural rule function (injected by wuchale at compile time)
|
|
8
|
-
* @returns The appropriate plural form with # replaced by count
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* plural(1, ['# item', '# items']) // "1 item"
|
|
12
|
-
* plural(5, ['# item', '# items']) // "5 items"
|
|
13
|
-
*/
|
|
14
|
-
export const plural = (count, candidates, rule = (n) => (n === 1 ? 0 : 1)) => {
|
|
15
|
-
const index = rule(count);
|
|
16
|
-
const template = candidates[index] ?? candidates[candidates.length - 1];
|
|
17
|
-
return template.replace(/#/g, String(count));
|
|
18
|
-
};
|