ember-primitives 0.49.0 → 0.50.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 (107) hide show
  1. package/bin/index.mjs +271 -0
  2. package/declarations/color-scheme.d.ts +1 -1
  3. package/declarations/color-scheme.d.ts.map +1 -1
  4. package/declarations/components/rating/public-types.d.ts +0 -4
  5. package/declarations/components/rating/public-types.d.ts.map +1 -1
  6. package/declarations/components/rating/rating.d.ts +9 -1
  7. package/declarations/components/rating/rating.d.ts.map +1 -1
  8. package/declarations/components/rating/stars.d.ts.map +1 -1
  9. package/declarations/components/rating/state.d.ts +4 -0
  10. package/declarations/components/rating/state.d.ts.map +1 -1
  11. package/declarations/components/rating/utils.d.ts +0 -1
  12. package/declarations/components/rating/utils.d.ts.map +1 -1
  13. package/dist/color-scheme.js +13 -4
  14. package/dist/color-scheme.js.map +1 -1
  15. package/dist/components/rating.js +1 -1
  16. package/dist/index.js +1 -1
  17. package/dist/{rating-CjBVsX6q.js → rating-BrIiwDLw.js} +21 -17
  18. package/dist/rating-BrIiwDLw.js.map +1 -0
  19. package/package.json +6 -2
  20. package/src/-private.ts +4 -0
  21. package/src/color-scheme.ts +177 -0
  22. package/src/components/-private/typed-elements.gts +13 -0
  23. package/src/components/-private/utils.ts +16 -0
  24. package/src/components/accordion/content.gts +34 -0
  25. package/src/components/accordion/header.gts +36 -0
  26. package/src/components/accordion/item.gts +55 -0
  27. package/src/components/accordion/public.ts +64 -0
  28. package/src/components/accordion/trigger.gts +32 -0
  29. package/src/components/accordion.gts +195 -0
  30. package/src/components/avatar.gts +108 -0
  31. package/src/components/dialog.gts +234 -0
  32. package/src/components/external-link.gts +14 -0
  33. package/src/components/form.gts +75 -0
  34. package/src/components/heading.gts +36 -0
  35. package/src/components/keys.gts +53 -0
  36. package/src/components/layout/hero.css +5 -0
  37. package/src/components/layout/hero.gts +17 -0
  38. package/src/components/layout/sticky-footer.css +9 -0
  39. package/src/components/layout/sticky-footer.gts +40 -0
  40. package/src/components/link.gts +172 -0
  41. package/src/components/menu.gts +373 -0
  42. package/src/components/one-time-password/buttons.gts +31 -0
  43. package/src/components/one-time-password/input.gts +198 -0
  44. package/src/components/one-time-password/otp.gts +130 -0
  45. package/src/components/one-time-password/utils.ts +201 -0
  46. package/src/components/one-time-password.gts +2 -0
  47. package/src/components/popover.gts +248 -0
  48. package/src/components/portal-targets.gts +136 -0
  49. package/src/components/portal.gts +194 -0
  50. package/src/components/progress.gts +154 -0
  51. package/src/components/rating/public-types.ts +44 -0
  52. package/src/components/rating/range.gts +22 -0
  53. package/src/components/rating/rating.gts +228 -0
  54. package/src/components/rating/stars.gts +60 -0
  55. package/src/components/rating/state.gts +144 -0
  56. package/src/components/rating/utils.ts +7 -0
  57. package/src/components/rating.gts +5 -0
  58. package/src/components/scroller.gts +179 -0
  59. package/src/components/shadowed.gts +110 -0
  60. package/src/components/switch.gts +103 -0
  61. package/src/components/tabs.gts +519 -0
  62. package/src/components/toggle-group.gts +265 -0
  63. package/src/components/toggle.gts +81 -0
  64. package/src/components/violations.css +105 -0
  65. package/src/components/violations.css.ts +1 -0
  66. package/src/components/visually-hidden.css +14 -0
  67. package/src/components/visually-hidden.gts +15 -0
  68. package/src/components/zoetrope/index.gts +358 -0
  69. package/src/components/zoetrope/styles.css +40 -0
  70. package/src/components/zoetrope/types.ts +65 -0
  71. package/src/components/zoetrope.ts +3 -0
  72. package/src/dom-context.gts +245 -0
  73. package/src/floating-ui/component.gts +186 -0
  74. package/src/floating-ui/middleware.ts +13 -0
  75. package/src/floating-ui/modifier.ts +183 -0
  76. package/src/floating-ui.ts +2 -0
  77. package/src/head.gts +37 -0
  78. package/src/helpers/body-class.ts +94 -0
  79. package/src/helpers/link.ts +125 -0
  80. package/src/helpers/service.ts +25 -0
  81. package/src/helpers.ts +2 -0
  82. package/src/iframe.ts +31 -0
  83. package/src/index.ts +43 -0
  84. package/src/load.gts +77 -0
  85. package/src/narrowing.ts +7 -0
  86. package/src/on-resize.ts +64 -0
  87. package/src/proper-links.ts +140 -0
  88. package/src/qp.ts +107 -0
  89. package/src/resize-observer.ts +132 -0
  90. package/src/service.ts +103 -0
  91. package/src/store.ts +72 -0
  92. package/src/styles.css.ts +5 -0
  93. package/src/tabster.ts +54 -0
  94. package/src/template-registry.ts +44 -0
  95. package/src/test-support/a11y.ts +50 -0
  96. package/src/test-support/dom.ts +112 -0
  97. package/src/test-support/otp.ts +64 -0
  98. package/src/test-support/rating.ts +144 -0
  99. package/src/test-support/routing.ts +62 -0
  100. package/src/test-support/zoetrope.ts +51 -0
  101. package/src/test-support.gts +6 -0
  102. package/src/type-utils.ts +1 -0
  103. package/src/utils.ts +75 -0
  104. package/src/viewport/in-viewport.gts +128 -0
  105. package/src/viewport/viewport.ts +122 -0
  106. package/src/viewport.ts +2 -0
  107. package/dist/rating-CjBVsX6q.js.map +0 -1
@@ -0,0 +1,154 @@
1
+ import Component from "@glimmer/component";
2
+ import { hash } from "@ember/helper";
3
+
4
+ import type { TOC } from "@ember/component/template-only";
5
+ import type { WithBoundArgs } from "@glint/template";
6
+
7
+ export interface Signature {
8
+ Element: HTMLDivElement;
9
+ Args: {
10
+ /**
11
+ * The current progress
12
+ * This may be less than 0 or more than `max`,
13
+ * but the resolved value (managed internally, and yielded out)
14
+ * does not exceed the range [0, max]
15
+ */
16
+ value: number;
17
+ /**
18
+ * The max value, defaults to 100
19
+ */
20
+ max?: number;
21
+ };
22
+ Blocks: {
23
+ default: [
24
+ {
25
+ /**
26
+ * The indicator element with some state applied.
27
+ * This can be used to style the progress of bar.
28
+ */
29
+ Indicator: WithBoundArgs<typeof Indicator, "value" | "max" | "percent">;
30
+ /**
31
+ * The value as a percent of how far along the indicator should be
32
+ * positioned, between 0 and 100.
33
+ * Will be rounded to two decimal places.
34
+ */
35
+ percent: number;
36
+ /**
37
+ * The value as a percent of how far along the indicator should be positioned,
38
+ * between 0 and 1
39
+ */
40
+ decimal: number;
41
+ /**
42
+ * The resolved value within the limits of the progress bar.
43
+ */
44
+ value: number;
45
+ },
46
+ ];
47
+ };
48
+ }
49
+
50
+ type ProgressState = "indeterminate" | "complete" | "loading";
51
+
52
+ const DEFAULT_MAX = 100;
53
+
54
+ /**
55
+ * Non-negative, non-NaN, non-Infinite, positive, rational
56
+ */
57
+ function isValidProgressNumber(value: number | undefined | null): value is number {
58
+ if (typeof value !== "number") return false;
59
+ if (!Number.isFinite(value)) return false;
60
+
61
+ return value >= 0;
62
+ }
63
+
64
+ function progressState(value: number | undefined | null, maxValue: number): ProgressState {
65
+ return value == null ? "indeterminate" : value === maxValue ? "complete" : "loading";
66
+ }
67
+
68
+ function getMax(userMax: number | undefined | null): number {
69
+ return isValidProgressNumber(userMax) ? userMax : DEFAULT_MAX;
70
+ }
71
+
72
+ function getValue(userValue: number | undefined | null, maxValue: number): number {
73
+ const max = getMax(maxValue);
74
+
75
+ if (!isValidProgressNumber(userValue)) {
76
+ return 0;
77
+ }
78
+
79
+ if (userValue > max) {
80
+ return max;
81
+ }
82
+
83
+ return userValue;
84
+ }
85
+
86
+ function getValueLabel(value: number, max: number) {
87
+ return `${Math.round((value / max) * 100)}%`;
88
+ }
89
+
90
+ const Indicator: TOC<{
91
+ Element: HTMLDivElement;
92
+ Args: { max: number; value: number; percent: number };
93
+ Blocks: { default: [] };
94
+ }> = <template>
95
+ <div
96
+ ...attributes
97
+ data-max={{@max}}
98
+ data-value={{@value}}
99
+ data-state={{progressState @value @max}}
100
+ data-percent={{@percent}}
101
+ >
102
+ {{yield}}
103
+ </div>
104
+ </template>;
105
+
106
+ export class Progress extends Component<Signature> {
107
+ get max() {
108
+ return getMax(this.args.max);
109
+ }
110
+
111
+ get value() {
112
+ return getValue(this.args.value, this.max);
113
+ }
114
+
115
+ get valueLabel() {
116
+ return getValueLabel(this.value, this.max);
117
+ }
118
+
119
+ get decimal() {
120
+ return this.value / this.max;
121
+ }
122
+
123
+ get percent() {
124
+ return Math.round(this.decimal * 100 * 100) / 100;
125
+ }
126
+
127
+ <template>
128
+ <div
129
+ ...attributes
130
+ aria-valuemax={{this.max}}
131
+ aria-valuemin="0"
132
+ aria-valuenow={{this.value}}
133
+ aria-valuetext={{this.valueLabel}}
134
+ role="progressbar"
135
+ data-value={{this.value}}
136
+ data-state={{progressState this.value this.max}}
137
+ data-max={{this.max}}
138
+ data-min="0"
139
+ data-percent={{this.percent}}
140
+ >
141
+
142
+ {{yield
143
+ (hash
144
+ Indicator=(component Indicator value=this.value max=this.max percent=this.percent)
145
+ value=this.value
146
+ percent=this.percent
147
+ decimal=this.decimal
148
+ )
149
+ }}
150
+ </div>
151
+ </template>
152
+ }
153
+
154
+ export default Progress;
@@ -0,0 +1,44 @@
1
+ import type { ComponentLike } from '@glint/template';
2
+
3
+ /**
4
+ * @public
5
+ */
6
+ export interface ComponentIcons {
7
+ /**
8
+ * It's possible to completely manage the state of an individual Icon yourself
9
+ * by passing a component that has ...attributes on its outer element and receives
10
+ * a @isSelected argument which is true for selected and false for unselected.
11
+ *
12
+ * There is also argument passed which is the percent-amount of selection if you want fractional ratings, @selectedPercent
13
+ */
14
+ icon: ComponentLike<{
15
+ Element: HTMLElement;
16
+ Args: {
17
+ /**
18
+ * Is this item selected?
19
+ */
20
+ isSelected: boolean;
21
+ /**
22
+ * Which number of item is this item within the overall rating group.
23
+ */
24
+ value: number;
25
+ /**
26
+ * Should this be marked as readonly
27
+ */
28
+ readonly: boolean;
29
+ };
30
+ }>;
31
+ }
32
+
33
+ /**
34
+ * @public
35
+ */
36
+ export interface StringIcons {
37
+ /**
38
+ * The symbol to use for an unselected variant of the icon
39
+ *
40
+ * Defaults to "★";
41
+ * Can change color when selected.
42
+ */
43
+ icon?: string;
44
+ }
@@ -0,0 +1,22 @@
1
+ import { on } from "@ember/modifier";
2
+
3
+ import type { TOC } from "@ember/component/template-only";
4
+
5
+ export const RatingRange: TOC<{
6
+ Element: HTMLInputElement;
7
+ Args: {
8
+ name: string;
9
+ max: number;
10
+ value: number;
11
+ handleChange: (event: Event) => void;
12
+ };
13
+ }> = <template>
14
+ <input
15
+ ...attributes
16
+ name={{@name}}
17
+ type="range"
18
+ max={{@max}}
19
+ value={{@value}}
20
+ {{on "change" @handleChange}}
21
+ />
22
+ </template>;
@@ -0,0 +1,228 @@
1
+ import Component from "@glimmer/component";
2
+ import { hash } from "@ember/helper";
3
+ import { on } from "@ember/modifier";
4
+
5
+ import { uniqueId } from "../../utils.ts";
6
+ import { RatingRange } from "./range.gts";
7
+ import { Stars } from "./stars.gts";
8
+ import { RatingState } from "./state.gts";
9
+
10
+ import type { ComponentIcons, StringIcons } from "./public-types.ts";
11
+ import type { WithBoundArgs } from "@glint/template";
12
+
13
+ export interface Signature {
14
+ /*
15
+ * The element all passed attributes / modifiers are applied to.
16
+ *
17
+ * This is a `<fieldset>`, becaues the rating elements are
18
+ * powered by a group of radio buttons.
19
+ */
20
+ Element: HTMLFieldSetElement;
21
+ Args: (ComponentIcons | StringIcons) & {
22
+ /**
23
+ * The number of stars/whichever-icon to show
24
+ *
25
+ * Defaults to 5
26
+ */
27
+ max?: number;
28
+
29
+ /**
30
+ * The current number of stars/whichever-icon to show as selected
31
+ *
32
+ * Defaults to 0
33
+ */
34
+ value?: number;
35
+
36
+ /**
37
+ * When generating the radio inputs, this changes what value of rating each radio
38
+ * input will be incremented by.
39
+ *
40
+ * e.g.: Set to 0.5 for half-star ratings.
41
+ *
42
+ * Defaults to 1
43
+ */
44
+ step?: number;
45
+
46
+ /**
47
+ * Prevents click events on the icons and sets aria-readonly.
48
+ *
49
+ * Also sets data-readonly=true on the wrapping element
50
+ */
51
+ readonly?: boolean;
52
+
53
+ /**
54
+ * Toggles the ability to interact with the rating component.
55
+ * When `true` (the default), the Rating component can be as a form input
56
+ * to gather user feedback.
57
+ *
58
+ * When false, only the `@value` will be shown, and it cannot be changed.
59
+ */
60
+ interactive?: boolean;
61
+
62
+ /**
63
+ * Callback when the selected rating changes.
64
+ * Can include half-ratings if the iconHalf argument is passed.
65
+ */
66
+ onChange?: (value: number) => void;
67
+ };
68
+
69
+ Blocks: {
70
+ default: [
71
+ rating: {
72
+ /**
73
+ * The maximum rating
74
+ */
75
+ max: number;
76
+ /**
77
+ * The maxium rating
78
+ */
79
+ total: number;
80
+ /**
81
+ * The current rating
82
+ */
83
+ value: number;
84
+ /**
85
+ * The name shared by the field group
86
+ */
87
+ name: string;
88
+ /**
89
+ * If the rating can be changed
90
+ */
91
+ isReadonly: boolean;
92
+ /**
93
+ * If the rating can be changed
94
+ */
95
+ isChangeable: boolean;
96
+ /**
97
+ * The stars / items radio group
98
+ */
99
+ Stars: WithBoundArgs<
100
+ typeof Stars,
101
+ "stars" | "icon" | "isReadonly" | "name" | "total" | "currentValue"
102
+ >;
103
+ /**
104
+ * Input range for adjusting the rating via fractional means
105
+ */
106
+ Range: WithBoundArgs<typeof RatingRange, "max" | "value" | "name" | "handleChange">;
107
+ },
108
+ ];
109
+ label: [
110
+ state: {
111
+ /**
112
+ * The current rating
113
+ */
114
+ value: number;
115
+
116
+ /**
117
+ * The maximum rating
118
+ */
119
+ total: number;
120
+ },
121
+ ];
122
+ };
123
+ }
124
+
125
+ export class Rating extends Component<Signature> {
126
+ name = `rating-${uniqueId()}`;
127
+
128
+ get icon() {
129
+ return this.args.icon ?? "★";
130
+ }
131
+
132
+ get isInteractive() {
133
+ return this.args.interactive ?? true;
134
+ }
135
+
136
+ get isChangeable() {
137
+ const readonly = this.args.readonly ?? false;
138
+
139
+ return !readonly && this.isInteractive;
140
+ }
141
+
142
+ get isReadonly() {
143
+ return !this.isChangeable;
144
+ }
145
+
146
+ get needsDescription() {
147
+ return !this.isInteractive;
148
+ }
149
+
150
+ <template>
151
+ <RatingState
152
+ @max={{@max}}
153
+ @step={{@step}}
154
+ @value={{@value}}
155
+ @name={{this.name}}
156
+ @readonly={{this.isReadonly}}
157
+ @onChange={{@onChange}}
158
+ as |r publicState|
159
+ >
160
+ <fieldset
161
+ class="ember-primitives__rating"
162
+ data-total={{r.total}}
163
+ data-value={{r.value}}
164
+ data-readonly={{this.isReadonly}}
165
+ {{! We use event delegation, this isn't a primary interactive -- we're capturing events from inputs }}
166
+ {{! template-lint-disable no-invalid-interactive }}
167
+ {{on "click" r.handleClick}}
168
+ ...attributes
169
+ >
170
+ {{#let
171
+ (component
172
+ Stars
173
+ stars=r.stars
174
+ icon=this.icon
175
+ isReadonly=this.isReadonly
176
+ name=this.name
177
+ total=r.total
178
+ currentValue=r.value
179
+ )
180
+ as |RatingStars|
181
+ }}
182
+
183
+ {{#if (has-block)}}
184
+ {{yield
185
+ (hash
186
+ max=r.total
187
+ total=r.total
188
+ value=r.value
189
+ name=this.name
190
+ isReadonly=this.isReadonly
191
+ isChangeable=this.isChangeable
192
+ Stars=RatingStars
193
+ Range=(component
194
+ RatingRange
195
+ step=r.step
196
+ max=r.total
197
+ value=r.value
198
+ name=this.name
199
+ handleChange=r.handleChange
200
+ )
201
+ )
202
+ }}
203
+ {{else}}
204
+ {{#if this.needsDescription}}
205
+ {{#if (has-block "label")}}
206
+ {{yield publicState to="label"}}
207
+ {{else}}
208
+ <span visually-hidden class="ember-primitives__rating__label">Rated
209
+ {{r.value}}
210
+ out of
211
+ {{r.total}}</span>
212
+ {{/if}}
213
+ {{else}}
214
+ {{#if (has-block "label")}}
215
+ <legend>
216
+ {{yield publicState to="label"}}
217
+ </legend>
218
+ {{/if}}
219
+ {{/if}}
220
+
221
+ <RatingStars />
222
+ {{/if}}
223
+ {{/let}}
224
+
225
+ </fieldset>
226
+ </RatingState>
227
+ </template>
228
+ }
@@ -0,0 +1,60 @@
1
+ import { uniqueId } from "../../utils.ts";
2
+ import { isString, lte } from "./utils.ts";
3
+
4
+ import type { ComponentIcons, StringIcons } from "./public-types.ts";
5
+ import type { TOC } from "@ember/component/template-only";
6
+
7
+ export const Stars: TOC<{
8
+ Args: {
9
+ // Configuration
10
+ stars: number[];
11
+ icon: StringIcons["icon"] | ComponentIcons["icon"];
12
+ isReadonly: boolean;
13
+
14
+ // HTML Boilerplate
15
+ name: string;
16
+
17
+ // State
18
+ currentValue: number;
19
+ total: number;
20
+ };
21
+ }> = <template>
22
+ <div class="ember-primitives__rating__items">
23
+ {{#each @stars as |star|}}
24
+ {{#let (uniqueId) as |id|}}
25
+ <span
26
+ class="ember-primitives__rating__item"
27
+ data-number={{star}}
28
+ data-selected={{lte star @currentValue}}
29
+ data-readonly={{@isReadonly}}
30
+ >
31
+ <label for="input-{{id}}">
32
+ <span visually-hidden>{{star}} star</span>
33
+ {{#if @icon}}
34
+ <span aria-hidden="true">
35
+ {{#if (isString @icon)}}
36
+ {{@icon}}
37
+ {{else}}
38
+ <@icon
39
+ @value={{star}}
40
+ @isSelected={{lte star @currentValue}}
41
+ @readonly={{@isReadonly}}
42
+ />
43
+ {{/if}}
44
+ </span>
45
+ {{/if}}
46
+ </label>
47
+
48
+ <input
49
+ id="input-{{id}}"
50
+ type="radio"
51
+ name={{@name}}
52
+ value={{star}}
53
+ readonly={{@isReadonly}}
54
+ checked={{Object.is star @currentValue}}
55
+ />
56
+ </span>
57
+ {{/let}}
58
+ {{/each}}
59
+ </div>
60
+ </template>;
@@ -0,0 +1,144 @@
1
+ import Component from "@glimmer/component";
2
+ import { cached } from "@glimmer/tracking";
3
+ import { assert } from "@ember/debug";
4
+ import { hash } from "@ember/helper";
5
+
6
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
7
+ // @ts-expect-error
8
+ import { localCopy } from "tracked-toolbox";
9
+
10
+ export class RatingState extends Component<{
11
+ Args: {
12
+ max: number | undefined;
13
+ value: number | undefined;
14
+ step: number | undefined;
15
+ readonly: boolean | undefined;
16
+ name: string;
17
+ onChange?: (value: number) => void;
18
+ };
19
+ Blocks: {
20
+ default: [
21
+ internalApi: {
22
+ stars: number[];
23
+ step: number;
24
+ value: number;
25
+ total: number;
26
+ handleClick: (event: Event) => void;
27
+ handleChange: (event: Event) => void;
28
+ setRating: (num: number) => void;
29
+ },
30
+ publicApi: {
31
+ value: number;
32
+ total: number;
33
+ },
34
+ ];
35
+ };
36
+ }> {
37
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
38
+ @localCopy("args.value") declare _value: number;
39
+
40
+ get value() {
41
+ return this._value ?? 0;
42
+ }
43
+
44
+ get step() {
45
+ return this.args.step ?? 1;
46
+ }
47
+
48
+ get max() {
49
+ return this.args.max ?? 5;
50
+ }
51
+
52
+ @cached
53
+ get stars() {
54
+ const result = [];
55
+
56
+ // 0 is "none selected"
57
+ let current = 0;
58
+
59
+ current += this.step;
60
+
61
+ while (current <= this.max) {
62
+ result.push(current);
63
+ current += this.step;
64
+ }
65
+
66
+ return result;
67
+ }
68
+
69
+ setRating = (value: number) => {
70
+ if (this.args.readonly) {
71
+ return;
72
+ }
73
+
74
+ if (value === this._value) {
75
+ this._value = 0;
76
+ } else {
77
+ this._value = value;
78
+ }
79
+
80
+ this.args.onChange?.(value);
81
+ };
82
+
83
+ setFromString = (value: unknown) => {
84
+ assert("[BUG]: value from input must be a string.", typeof value === "string");
85
+
86
+ const num = parseFloat(value);
87
+
88
+ if (isNaN(num)) {
89
+ // something went wrong.
90
+ // Since we're using event delegation,
91
+ // this could be from an unrelated input
92
+ return;
93
+ }
94
+
95
+ this.setRating(num);
96
+ };
97
+
98
+ /**
99
+ * Click events are captured by
100
+ * - radio changes (mouse and keyboard)
101
+ * - but only range clicks
102
+ */
103
+ handleClick = (event: Event) => {
104
+ // Since we're doing event delegation on a click, we want to make sure
105
+ // we don't do anything on other elements
106
+ const isValid =
107
+ event.target instanceof HTMLInputElement &&
108
+ event.target.name === this.args.name &&
109
+ event.target.type === "radio";
110
+
111
+ if (!isValid) return;
112
+
113
+ const selected = event.target?.value;
114
+
115
+ this.setFromString(selected);
116
+ };
117
+
118
+ /**
119
+ * Only attached to a range element, if present.
120
+ * Range elements don't fire click events on keyboard usage, like radios do
121
+ */
122
+ handleChange = (event: Event) => {
123
+ const isValid = event.target !== null && "value" in event.target;
124
+
125
+ if (!isValid) return;
126
+
127
+ this.setFromString(event.target.value);
128
+ };
129
+
130
+ <template>
131
+ {{yield
132
+ (hash
133
+ stars=this.stars
134
+ total=this.stars.length
135
+ handleClick=this.handleClick
136
+ handleChange=this.handleChange
137
+ setRating=this.setRating
138
+ value=this.value
139
+ step=this.step
140
+ )
141
+ (hash total=this.stars.length value=this.value)
142
+ }}
143
+ </template>
144
+ }
@@ -0,0 +1,7 @@
1
+ export function isString(x: unknown) {
2
+ return typeof x === 'string';
3
+ }
4
+
5
+ export function lte(a: number, b: number) {
6
+ return a <= b;
7
+ }
@@ -0,0 +1,5 @@
1
+ export { Rating } from "./rating/rating.gts";
2
+
3
+ import type { ComponentIcons } from "./rating/public-types.ts";
4
+
5
+ export type IconType = ComponentIcons["icon"];