react-awesome-stars-rating 0.16.2 → 1.0.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.
package/MIGRATION.md ADDED
@@ -0,0 +1,81 @@
1
+ # Migration guide
2
+
3
+ ## 0.x → 1.0
4
+
5
+ Every prop is unchanged. `id`, `value`, `onChange`, `isEdit`, `isHalf`, `count`,
6
+ `size`, `starGap`, `className`, `primaryColor`, `secondaryColor` and
7
+ `isArrowSubmit` all keep their names, types and defaults, so component usage
8
+ does not need to change:
9
+
10
+ ```tsx
11
+ <ReactStarsRating value={3.5} onChange={setValue} isHalf size={32} />
12
+ ```
13
+
14
+ The breaking changes are all in packaging.
15
+
16
+ ### React 19 is required, and React is now a peer dependency
17
+
18
+ 0.x declared `react` and `react-dom` as **runtime dependencies** (`^17.0.2`),
19
+ which could install a second copy of React alongside your own. 1.0 declares them
20
+ as peer dependencies and requires React 19 or newer.
21
+
22
+ ```bash
23
+ npm install react@^19 react-dom@^19 react-awesome-stars-rating
24
+ ```
25
+
26
+ If you are still on React 16, 17 or 18, stay on `0.16.2`.
27
+
28
+ ### Entry points moved
29
+
30
+ 0.x published a single `dist/index.js` for both `main` and `module`. 1.0 uses an
31
+ exports map:
32
+
33
+ | Consumer | Resolves to |
34
+ | :--------------- | :------------------- |
35
+ | `import` | `dist/index.mjs` |
36
+ | `require` | `dist/index.cjs` |
37
+ | `<script>` / CDN | `dist/index.umd.cjs` |
38
+
39
+ The package is now `"type": "module"`. Normal imports are unaffected:
40
+
41
+ ```tsx
42
+ import ReactStarsRating from 'react-awesome-stars-rating';
43
+ ```
44
+
45
+ **Deep imports no longer resolve.** 0.x shipped `dist/star.js`,
46
+ `dist/gradient.js` and `dist/styles.js` as separate files; 1.0 bundles them.
47
+ Anything reaching into `react-awesome-stars-rating/dist/...` must import from
48
+ the package root instead.
49
+
50
+ ### Undocumented DOM attributes removed
51
+
52
+ These were only ever test hooks, and they are no longer rendered:
53
+
54
+ `data-testid`, `data-value`, `data-submitted`, `data-stars`, `data-offset`
55
+
56
+ If your tests or styles targeted them, use the accessible API instead — it is
57
+ stable and part of the public surface:
58
+
59
+ ```ts
60
+ // before
61
+ container.querySelector('[data-testid="react-awesome-stars-rating"]');
62
+ expect(el).toHaveAttribute('data-value', '3');
63
+
64
+ // after
65
+ screen.getByRole('slider', { name: 'Star rating' });
66
+ expect(el).toHaveAttribute('aria-valuenow', '3');
67
+ ```
68
+
69
+ The `star`, `star-1`, `star-2` … class names on the star wrappers are unchanged
70
+ and still safe to style.
71
+
72
+ ## What you get in return
73
+
74
+ - TypeScript types ship with the package. 0.x had none.
75
+ - No runtime dependencies at all: `prop-types`, `react` and `react-dom` are gone
76
+ from `dependencies`.
77
+ - `role="slider"` with `aria-valuemin`, `aria-valuemax`, `aria-valuenow` and a
78
+ readable `aria-valuetext`, plus new `ariaLabel` and `ariaLabelledBy` props.
79
+ - The generated `id` comes from React's `useId` instead of `Date.now()`, so
80
+ server and client markup match.
81
+ - The package carries `'use client'` and works in a React Server Component tree.
package/README.md CHANGED
@@ -1,72 +1,203 @@
1
- # React Awesome Stars Rating &middot; [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/fedoryakubovich/react-awesome-stars-rating/blob/master/LICENSE) [![npm version](https://img.shields.io/npm/v/react-awesome-stars-rating.svg?style=flat)](https://www.npmjs.com/package/react-awesome-stars-rating) [![Build Status](https://www.travis-ci.com/fedoryakubovich/react-awesome-stars-rating.svg?branch=master)](https://www.travis-ci.com/) [![codecov](https://codecov.io/gh/fedoryakubovich/react-awesome-stars-rating/branch/main/graph/badge.svg?token=JPQCSB8NTN)](https://codecov.io/gh/fedoryakubovich/react-awesome-stars-rating)
1
+ # React Awesome Stars Rating
2
2
 
3
- React Awesome Stars Rating is a simple star component with easy integration for your React applications.
3
+ [![npm](https://img.shields.io/npm/v/react-awesome-stars-rating)](https://www.npmjs.com/package/react-awesome-stars-rating)
4
+ [![CI](https://github.com/fedoryakubovich/react-awesome-stars-rating/actions/workflows/ci.yml/badge.svg)](https://github.com/fedoryakubovich/react-awesome-stars-rating/actions/workflows/ci.yml)
5
+ [![license](https://img.shields.io/npm/l/react-awesome-stars-rating)](https://github.com/fedoryakubovich/react-awesome-stars-rating/blob/main/LICENSE)
4
6
 
5
- ## Table of Contents
7
+ An accessible star rating component for React. Half stars from pointer position, full keyboard control, any scale or palette — in about 1.5 kB gzipped with no runtime dependencies.
6
8
 
7
- - [Previews](#previews)
8
- - [Features](#features)
9
- - [Installation](#installation)
10
- - [Usage](#usage)
11
- - [Examples](#examples)
12
- - [Documentation](#documentation)
9
+ **[Live demo](https://react-awesome-stars-rating.vercel.app)** · **[Storybook](https://react-awesome-stars-rating.vercel.app/storybook)**
13
10
 
14
- ## Previews
11
+ ![react-awesome-stars-rating preview](https://raw.githubusercontent.com/fedoryakubovich/react-awesome-stars-rating/main/images/gifs/react-awesome-stars-rating.gif)
15
12
 
16
- ![react-awesome-stars-rating preview](https://github.com/fedoryakubovich/react-awesome-stars-rating/blob/master/images/gifs/react-awesome-stars-rating.gif)
13
+ ## Highlights
17
14
 
18
- ## Features
15
+ - ~1.5 kB gzipped, no runtime dependencies
16
+ - Half-star precision from pointer position, plus arrow-key stepping
17
+ - `role="slider"` with live `aria-valuenow` / `aria-valuetext`, verified with axe-core
18
+ - ESM + CJS with correct types for each, and a UMD bundle for CDN use
19
+ - Ships `'use client'`, so it drops into a React Server Component tree unwrapped
20
+ - Works with React Hook Form, Formik and TanStack Form
19
21
 
20
- - Half stars
21
- - Custom size and color
22
- - Value shows with high precision
23
- - Easy integration with Redux
24
- - Accessibility
25
- - SVG Icons
22
+ ## Requirements
23
+
24
+ React 19 or newer (`react` and `react-dom` are peer dependencies).
25
+
26
+ Upgrading from 0.x? See the [migration guide](https://github.com/fedoryakubovich/react-awesome-stars-rating/blob/main/MIGRATION.md).
26
27
 
27
28
  ## Installation
28
29
 
29
- `npm install react-awesome-stars-rating`
30
+ ```bash
31
+ npm install react-awesome-stars-rating
32
+ ```
33
+
34
+ ### CDN
30
35
 
31
- ## Usage
36
+ React 19 no longer publishes UMD builds, so load the package as a module:
32
37
 
33
- ```javascript
34
- import React from 'react';
35
- import ReactDOM from 'react-dom';
38
+ ```html
39
+ <script type="module">
40
+ import React from 'https://esm.sh/react@19';
41
+ import { createRoot } from 'https://esm.sh/react-dom@19/client';
42
+ import ReactStarsRating from 'https://esm.sh/react-awesome-stars-rating';
36
43
 
44
+ createRoot(document.getElementById('root')).render(
45
+ React.createElement(ReactStarsRating, { value: 3.5, isEdit: false }),
46
+ );
47
+ </script>
48
+ ```
49
+
50
+ A UMD bundle is still published at `dist/index.umd.cjs` for pages that already
51
+ expose React as a global, and expects `window.React` to be present.
52
+
53
+ ## Usage
54
+
55
+ ```tsx
37
56
  import ReactStarsRating from 'react-awesome-stars-rating';
38
57
 
39
- const onChange = (value) => {
40
- console.log(`React Stars Rating value is ${value}`);
58
+ const onChange = (value: number) => {
59
+ console.log(`Rating: ${value}`);
41
60
  };
42
61
 
43
- const ReactStarsExample = ({ value }) => {
44
- return <ReactStarsRating onChange={onChange} value={value} />;
45
- };
62
+ export default function Example() {
63
+ return <ReactStarsRating onChange={onChange} value={3.5} />;
64
+ }
65
+ ```
66
+
67
+ ## Props
68
+
69
+ | Name | Description | Type | Default |
70
+ | :------------- | :---------------------------------------- | :------------------------ | :-------------- |
71
+ | id | Identifier | `string` | auto-generated |
72
+ | value | Current value | `number` | `0` |
73
+ | onChange | Called when value changes | `(value: number) => void` | `() => {}` |
74
+ | isEdit | Editing mode | `boolean` | `true` |
75
+ | isHalf | Allow half stars | `boolean` | `true` |
76
+ | count | Number of stars | `number` | `5` |
77
+ | size | Star size (px) | `number` | `25` |
78
+ | starGap | Gap between stars | `number` | `0` |
79
+ | className | Container class | `string` | `''` |
80
+ | primaryColor | Active star color | `string` | `'orange'` |
81
+ | secondaryColor | Inactive star color | `string` | `'grey'` |
82
+ | isArrowSubmit | Arrow keys trigger `onChange` immediately | `boolean` | `false` |
83
+ | ariaLabel | Accessible label (if no `ariaLabelledBy`) | `string` | `'Star rating'` |
84
+ | ariaLabelledBy | ID of element that labels the control | `string` | `undefined` |
85
+
86
+ ## Keyboard and accessibility
87
+
88
+ The control renders as a single `role="slider"` element with `aria-valuemin`, `aria-valuemax`, `aria-valuenow` and a readable `aria-valuetext` ("3.5 of 5"). Values outside `0…count` are clamped before they are reported.
89
+
90
+ | Key | Behaviour |
91
+ | :--------- | :------------------------------------------------- |
92
+ | `←` / `→` | Step by half a star (`isHalf`) or a whole star |
93
+ | `Enter` | Report the current value through `onChange` |
94
+ | `Tab` away | Report the current value, then leave the tab order |
95
+
96
+ With `isArrowSubmit`, each arrow step reports through `onChange` immediately rather than waiting for `Enter` or blur.
97
+
98
+ When `isEdit` is `false` the control is inert: no hover preview, no keyboard, and `tabIndex={-1}`.
99
+
100
+ ## Server components
101
+
102
+ The package carries the `'use client'` directive, so it can be imported directly from a server component in the Next.js App Router without a wrapper.
103
+
104
+ ## Form Integrations
46
105
 
47
- ReactDOM.render(<ReactStarsExample />, document.getElementById('root'));
106
+ ### React Hook Form
107
+
108
+ ```tsx
109
+ import { Controller, useForm } from 'react-hook-form';
110
+ import ReactStarsRating from 'react-awesome-stars-rating';
111
+
112
+ const { control } = useForm({ defaultValues: { rating: 3.5 } });
113
+
114
+ <Controller
115
+ control={control}
116
+ name="rating"
117
+ render={({ field }) => (
118
+ <ReactStarsRating value={field.value} onChange={field.onChange} />
119
+ )}
120
+ />;
121
+ ```
122
+
123
+ ### Formik
124
+
125
+ ```tsx
126
+ import { Field } from 'formik';
127
+ import ReactStarsRating from 'react-awesome-stars-rating';
128
+
129
+ <Field name="rating">
130
+ {({ field, form }) => (
131
+ <ReactStarsRating
132
+ value={field.value}
133
+ onChange={(value) => form.setFieldValue('rating', value)}
134
+ />
135
+ )}
136
+ </Field>;
137
+ ```
138
+
139
+ ### TanStack Form
140
+
141
+ ```tsx
142
+ import { useForm } from '@tanstack/react-form';
143
+ import ReactStarsRating from 'react-awesome-stars-rating';
144
+
145
+ type FormValues = { rating: number };
146
+
147
+ const form = useForm<FormValues>({
148
+ defaultValues: { rating: 3.5 },
149
+ onSubmit: ({ value }) => {
150
+ console.log('tanstack-form submit', value);
151
+ },
152
+ });
153
+
154
+ <form
155
+ onSubmit={(e) => {
156
+ e.preventDefault();
157
+ void form.handleSubmit();
158
+ }}
159
+ >
160
+ <form.Field name="rating">
161
+ {(field) => (
162
+ <ReactStarsRating
163
+ value={field.state.value}
164
+ onChange={field.handleChange}
165
+ />
166
+ )}
167
+ </form.Field>
168
+ </form>;
48
169
  ```
49
170
 
50
- ## Documentation
51
-
52
- | Name | Description | Type | Default |
53
- | :------------- | :------------------------------------------------------- | :------- | :-------------- |
54
- | id | Identifier | String | `${Date.now()}` |
55
- | value | Value | Number | 0 |
56
- | onChange | A function, that will be invoked when value have changed | Function | null |
57
- | isEdit | If `true` the rating is in editing mode | Boolean | true |
58
- | isHalf | If `true` half stars are available | Boolean | true |
59
- | count | Count of the stars | Number | 5 |
60
- | size | Size of the stars | Number | 25 |
61
- | starGap | Gap between the stars | Number | 0 |
62
- | className | Class name for button container | String | '' |
63
- | primaryColor | Star's color when star is active | String | 'orange' |
64
- | secondaryColor | Star's color when star isn't active | String | 'grey' |
65
- | isArrowSubmit | Left arrow or right arrow click onvokes onChange | Boolean | false |
66
-
67
- ## Examples
68
-
69
- You can see live examples by below links:
70
-
71
- - [Simple Example](https://repl.it/@fedoryakubovich/React-Awesome-Stars-Rating-Simple-Example)
72
- - [Integration](https://repl.it/@fedoryakubovich/React-Awesome-Stars-Rating-Redux-Form-Example) with [redux-form](https://github.com/erikras/redux-form)
171
+ ## Development
172
+
173
+ ```bash
174
+ npm install
175
+ npm run dev # demo app
176
+ npm run storybook # Storybook
177
+ npm run test # Vitest
178
+ npm run coverage # Vitest with coverage thresholds
179
+ npm run lint # ESLint
180
+ npm run format # Prettier check
181
+ npm run typecheck # TypeScript
182
+ npm run build # library build (ESM + CJS + UMD + types) → dist/
183
+ npm run verify:package # render every entry point from dist/
184
+ npm run lint:package # publint + are-the-types-wrong on the packed tarball
185
+ npm run size # size-limit budgets for every entry point
186
+ npm run build:site # demo site → dist-site/
187
+ ```
188
+
189
+ Pre-commit (Husky) runs lint-staged (Prettier + ESLint on staged files) and commitlint (Conventional Commits).
190
+
191
+ ## CI / Releases
192
+
193
+ - **CI** — on push/PR to `main`: format, lint, commitlint, typecheck, tests, coverage, build, package verification, publint/attw, size budgets, Storybook and site builds.
194
+ - **Deploy** — Vercel builds the demo site on every push (see `vercel.json`), serving Storybook at `/storybook`.
195
+ - **Release** — [semantic-release](https://github.com/semantic-release/semantic-release) on push to `main`: analyzes Conventional Commits, publishes to npm and creates a GitHub release.
196
+
197
+ Publishing uses npm trusted publishing (OIDC) from `.github/workflows/ci.yml`; the workflow does not use an npm token.
198
+
199
+ No manual tagging: merge to `main` with commits like `feat: ...` or `fix: ...` to trigger a release.
200
+
201
+ ## License
202
+
203
+ MIT
@@ -0,0 +1,12 @@
1
+ type GradientProps = {
2
+ primaryColor: string;
3
+ secondaryColor: string;
4
+ offset?: number;
5
+ index: number;
6
+ value: number;
7
+ fullId: string;
8
+ halfId: string;
9
+ noneId: string;
10
+ };
11
+ declare const Gradient: ({ primaryColor, secondaryColor, offset, index, value, fullId, halfId, noneId, }: GradientProps) => import("react").JSX.Element | null;
12
+ export default Gradient;
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use client";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});let e=require("react"),t=require("react/jsx-runtime");var n=({primaryColor:e,secondaryColor:n,offset:r=50,index:i,value:a,fullId:o,halfId:s,noneId:c})=>{let l=r;return i===1&&(l=Math.round(a%1*1e4)/100),i===1?(0,t.jsxs)(`defs`,{children:[(0,t.jsx)(`linearGradient`,{id:o,children:(0,t.jsx)(`stop`,{offset:`100%`,stopColor:e})}),(0,t.jsx)(`linearGradient`,{id:c,children:(0,t.jsx)(`stop`,{offset:`100%`,stopColor:n})}),(0,t.jsxs)(`linearGradient`,{id:s,children:[(0,t.jsx)(`stop`,{offset:`${l}%`,stopColor:e}),(0,t.jsx)(`stop`,{offset:`${l}%`,stopColor:n})]})]}):null},r=({viewBox:e=`0 0 306 306`,size:r,onMouseMove:i,onMouseLeave:a,onChange:o,index:s,value:c,isHalf:l,primaryColor:u,secondaryColor:d,fill:f,offset:p=50,fullId:m,halfId:h,noneId:g})=>{let _=f;return _=s<=c?`url(#${m})`:l&&Math.ceil(c)===s?`url(#${h})`:`url(#${g})`,(0,t.jsxs)(`svg`,{width:r,viewBox:e,xmlns:`http://www.w3.org/2000/svg`,xmlnsXlink:`http://www.w3.org/1999/xlink`,onMouseLeave:a,onClick:o,onMouseMove:i,children:[(0,t.jsx)(n,{primaryColor:u,secondaryColor:d,offset:p,index:s,value:c,fullId:m,halfId:h,noneId:g}),(0,t.jsx)(`polygon`,{fill:_,points:`153,230.775 247.35,299.625 211.65,187.425 306,121.125 191.25,121.125 153,6.375 114.75,121.125 0,121.125 94.35,187.425 58.65,299.625`,pointerEvents:`none`})]})},i={activeContainer:{border:`none`,display:`inline-flex`},inActiveContainer:{border:`none`,outline:0,display:`inline-flex`}},a=({id:n,value:a=0,onChange:o=()=>{},isEdit:s=!0,isHalf:c=!0,count:l=5,size:u=25,starGap:d=0,className:f=``,primaryColor:p=`orange`,secondaryColor:m=`grey`,isArrowSubmit:h=!1,ariaLabel:g=`Star rating`,ariaLabelledBy:_})=>{let v=(0,e.useId)().replace(/:/g,``),y=n??`react-stars-rating-${v}`,[b,x]=(0,e.useState)(()=>({sourceValue:a,displayValue:a})),[S,C]=(0,e.useState)(!1),w=b.sourceValue===a?b.displayValue:a,T=e=>{x({sourceValue:a,displayValue:e})},E=(0,e.useMemo)(()=>`fullId-${y}`,[y]),D=(0,e.useMemo)(()=>`halfId-${y}`,[y]),O=(0,e.useMemo)(()=>`noneId-${y}`,[y]),k=e=>e.clientX-e.currentTarget.getBoundingClientRect().left>u/2,A=(e,t)=>c?k(e)?t:t-.5:t,j=(e,t)=>{s&&T(A(e,t))},M=()=>{s&&T(a||0)},N=()=>{o(w),C(!0)},P=(e,t)=>{if(!s)return;let n=A(e,t);T(n),o(n)},F=e=>{let t=w;t%1!=.5&&(t=Math.round(t)),t=Math.min(Math.max(t+e,0),l),T(t),h&&o(t)},I=e=>{switch(e.key){case`ArrowLeft`:F(c?-.5:-1);break;case`ArrowRight`:F(c?.5:1);break;case`Enter`:o(w)}},L=()=>Array.from({length:l},(e,n)=>{let i=n+1,a=i===l?void 0:{paddingRight:d};return(0,t.jsx)(`span`,{className:`star star-${i}`,style:a,children:(0,t.jsx)(r,{index:i,value:w,size:u,isHalf:c,fullId:E,halfId:D,noneId:O,primaryColor:p,secondaryColor:m,onMouseMove:e=>j(e,i),onMouseLeave:M,onChange:e=>P(e,i)})},`react-stars-rating-char${i}`)}),R=(s||h)&&!S,z=Math.min(Math.max(w,0),l);return(0,t.jsx)(`span`,{id:y,role:`slider`,"aria-label":_?void 0:g,"aria-labelledby":_,"aria-valuemin":0,"aria-valuemax":l,"aria-valuenow":z,"aria-valuetext":`${z} of ${l}`,tabIndex:R?0:-1,onKeyDown:R?I:void 0,onBlur:R?N:void 0,style:s?i.activeContainer:i.inActiveContainer,className:f,children:L()})};exports.ReactStarsRating=a,exports.default=a;
@@ -0,0 +1,108 @@
1
+ export type ReactStarsRatingProps = {
2
+ /**
3
+ * `id` of the rendered element. Defaults to a generated, SSR-safe id, so
4
+ * only set this when something else needs to reference the control.
5
+ */
6
+ id?: string;
7
+ /**
8
+ * Current rating. Values outside `0` to {@link ReactStarsRatingProps.count}
9
+ * are clamped before they are reported to assistive technology.
10
+ *
11
+ * @defaultValue 0
12
+ */
13
+ value?: number;
14
+ /**
15
+ * Called with the new rating on click, on `Enter`, and on blur — and on
16
+ * every arrow key when {@link ReactStarsRatingProps.isArrowSubmit} is set.
17
+ * Hovering never calls it.
18
+ */
19
+ onChange?: (value: number) => void;
20
+ /**
21
+ * Whether the rating can be changed. When `false` the control has no hover
22
+ * preview, no keyboard handling, and is removed from the tab order.
23
+ *
24
+ * @defaultValue true
25
+ */
26
+ isEdit?: boolean;
27
+ /**
28
+ * Whether half stars can be selected. When `true` the half of the star the
29
+ * pointer is over decides between `n - 0.5` and `n`, and the arrow keys step
30
+ * by `0.5` instead of `1`.
31
+ *
32
+ * @defaultValue true
33
+ */
34
+ isHalf?: boolean;
35
+ /**
36
+ * How many stars to render. Also becomes `aria-valuemax`.
37
+ *
38
+ * @defaultValue 5
39
+ */
40
+ count?: number;
41
+ /**
42
+ * Width of one star, in pixels.
43
+ *
44
+ * @defaultValue 25
45
+ */
46
+ size?: number;
47
+ /**
48
+ * Space between stars, in pixels. Applied as right padding to every star
49
+ * except the last.
50
+ *
51
+ * @defaultValue 0
52
+ */
53
+ starGap?: number;
54
+ /**
55
+ * Class name for the container element. The stars themselves always carry
56
+ * `star` and `star-1`, `star-2`, … class names.
57
+ *
58
+ * @defaultValue ''
59
+ */
60
+ className?: string;
61
+ /**
62
+ * Any CSS color for the filled part of a star.
63
+ *
64
+ * @defaultValue 'orange'
65
+ */
66
+ primaryColor?: string;
67
+ /**
68
+ * Any CSS color for the empty part of a star.
69
+ *
70
+ * @defaultValue 'grey'
71
+ */
72
+ secondaryColor?: string;
73
+ /**
74
+ * Report every arrow-key step through
75
+ * {@link ReactStarsRatingProps.onChange} immediately, instead of waiting for
76
+ * `Enter` or blur.
77
+ *
78
+ * @defaultValue false
79
+ */
80
+ isArrowSubmit?: boolean;
81
+ /**
82
+ * Accessible name for the control. Ignored when
83
+ * {@link ReactStarsRatingProps.ariaLabelledBy} is set.
84
+ *
85
+ * @defaultValue 'Star rating'
86
+ */
87
+ ariaLabel?: string;
88
+ /**
89
+ * `id` of an element that labels this control, for when the label already
90
+ * exists on the page. Takes precedence over
91
+ * {@link ReactStarsRatingProps.ariaLabel}.
92
+ */
93
+ ariaLabelledBy?: string;
94
+ };
95
+ /**
96
+ * A star rating control. Renders as a single `role="slider"` element that
97
+ * reports its value through `aria-valuenow` and `aria-valuetext`.
98
+ *
99
+ * @example
100
+ * ```tsx
101
+ * const [value, setValue] = useState(3.5);
102
+ *
103
+ * <ReactStarsRating value={value} onChange={setValue} isHalf size={32} />
104
+ * ```
105
+ */
106
+ declare const ReactStarsRating: ({ id, value, onChange, isEdit, isHalf, count, size, starGap, className, primaryColor, secondaryColor, isArrowSubmit, ariaLabel, ariaLabelledBy, }: ReactStarsRatingProps) => import("react").JSX.Element;
107
+ export { ReactStarsRating };
108
+ export default ReactStarsRating;
@@ -0,0 +1,108 @@
1
+ export type ReactStarsRatingProps = {
2
+ /**
3
+ * `id` of the rendered element. Defaults to a generated, SSR-safe id, so
4
+ * only set this when something else needs to reference the control.
5
+ */
6
+ id?: string;
7
+ /**
8
+ * Current rating. Values outside `0` to {@link ReactStarsRatingProps.count}
9
+ * are clamped before they are reported to assistive technology.
10
+ *
11
+ * @defaultValue 0
12
+ */
13
+ value?: number;
14
+ /**
15
+ * Called with the new rating on click, on `Enter`, and on blur — and on
16
+ * every arrow key when {@link ReactStarsRatingProps.isArrowSubmit} is set.
17
+ * Hovering never calls it.
18
+ */
19
+ onChange?: (value: number) => void;
20
+ /**
21
+ * Whether the rating can be changed. When `false` the control has no hover
22
+ * preview, no keyboard handling, and is removed from the tab order.
23
+ *
24
+ * @defaultValue true
25
+ */
26
+ isEdit?: boolean;
27
+ /**
28
+ * Whether half stars can be selected. When `true` the half of the star the
29
+ * pointer is over decides between `n - 0.5` and `n`, and the arrow keys step
30
+ * by `0.5` instead of `1`.
31
+ *
32
+ * @defaultValue true
33
+ */
34
+ isHalf?: boolean;
35
+ /**
36
+ * How many stars to render. Also becomes `aria-valuemax`.
37
+ *
38
+ * @defaultValue 5
39
+ */
40
+ count?: number;
41
+ /**
42
+ * Width of one star, in pixels.
43
+ *
44
+ * @defaultValue 25
45
+ */
46
+ size?: number;
47
+ /**
48
+ * Space between stars, in pixels. Applied as right padding to every star
49
+ * except the last.
50
+ *
51
+ * @defaultValue 0
52
+ */
53
+ starGap?: number;
54
+ /**
55
+ * Class name for the container element. The stars themselves always carry
56
+ * `star` and `star-1`, `star-2`, … class names.
57
+ *
58
+ * @defaultValue ''
59
+ */
60
+ className?: string;
61
+ /**
62
+ * Any CSS color for the filled part of a star.
63
+ *
64
+ * @defaultValue 'orange'
65
+ */
66
+ primaryColor?: string;
67
+ /**
68
+ * Any CSS color for the empty part of a star.
69
+ *
70
+ * @defaultValue 'grey'
71
+ */
72
+ secondaryColor?: string;
73
+ /**
74
+ * Report every arrow-key step through
75
+ * {@link ReactStarsRatingProps.onChange} immediately, instead of waiting for
76
+ * `Enter` or blur.
77
+ *
78
+ * @defaultValue false
79
+ */
80
+ isArrowSubmit?: boolean;
81
+ /**
82
+ * Accessible name for the control. Ignored when
83
+ * {@link ReactStarsRatingProps.ariaLabelledBy} is set.
84
+ *
85
+ * @defaultValue 'Star rating'
86
+ */
87
+ ariaLabel?: string;
88
+ /**
89
+ * `id` of an element that labels this control, for when the label already
90
+ * exists on the page. Takes precedence over
91
+ * {@link ReactStarsRatingProps.ariaLabel}.
92
+ */
93
+ ariaLabelledBy?: string;
94
+ };
95
+ /**
96
+ * A star rating control. Renders as a single `role="slider"` element that
97
+ * reports its value through `aria-valuenow` and `aria-valuetext`.
98
+ *
99
+ * @example
100
+ * ```tsx
101
+ * const [value, setValue] = useState(3.5);
102
+ *
103
+ * <ReactStarsRating value={value} onChange={setValue} isHalf size={32} />
104
+ * ```
105
+ */
106
+ declare const ReactStarsRating: ({ id, value, onChange, isEdit, isHalf, count, size, starGap, className, primaryColor, secondaryColor, isArrowSubmit, ariaLabel, ariaLabelledBy, }: ReactStarsRatingProps) => import("react").JSX.Element;
107
+ export { ReactStarsRating };
108
+ export default ReactStarsRating;
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ "use client";import{useId as e,useMemo as t,useState as n}from"react";import{jsx as r,jsxs as i}from"react/jsx-runtime";var a=({primaryColor:e,secondaryColor:t,offset:n=50,index:a,value:o,fullId:s,halfId:c,noneId:l})=>{let u=n;return a===1&&(u=Math.round(o%1*1e4)/100),a===1?i(`defs`,{children:[r(`linearGradient`,{id:s,children:r(`stop`,{offset:`100%`,stopColor:e})}),r(`linearGradient`,{id:l,children:r(`stop`,{offset:`100%`,stopColor:t})}),i(`linearGradient`,{id:c,children:[r(`stop`,{offset:`${u}%`,stopColor:e}),r(`stop`,{offset:`${u}%`,stopColor:t})]})]}):null},o=({viewBox:e=`0 0 306 306`,size:t,onMouseMove:n,onMouseLeave:o,onChange:s,index:c,value:l,isHalf:u,primaryColor:d,secondaryColor:f,fill:p,offset:m=50,fullId:h,halfId:g,noneId:_})=>{let v=p;return v=c<=l?`url(#${h})`:u&&Math.ceil(l)===c?`url(#${g})`:`url(#${_})`,i(`svg`,{width:t,viewBox:e,xmlns:`http://www.w3.org/2000/svg`,xmlnsXlink:`http://www.w3.org/1999/xlink`,onMouseLeave:o,onClick:s,onMouseMove:n,children:[r(a,{primaryColor:d,secondaryColor:f,offset:m,index:c,value:l,fullId:h,halfId:g,noneId:_}),r(`polygon`,{fill:v,points:`153,230.775 247.35,299.625 211.65,187.425 306,121.125 191.25,121.125 153,6.375 114.75,121.125 0,121.125 94.35,187.425 58.65,299.625`,pointerEvents:`none`})]})},s={activeContainer:{border:`none`,display:`inline-flex`},inActiveContainer:{border:`none`,outline:0,display:`inline-flex`}},c=({id:i,value:a=0,onChange:c=()=>{},isEdit:l=!0,isHalf:u=!0,count:d=5,size:f=25,starGap:p=0,className:m=``,primaryColor:h=`orange`,secondaryColor:g=`grey`,isArrowSubmit:_=!1,ariaLabel:v=`Star rating`,ariaLabelledBy:y})=>{let b=e().replace(/:/g,``),x=i??`react-stars-rating-${b}`,[S,C]=n(()=>({sourceValue:a,displayValue:a})),[w,T]=n(!1),E=S.sourceValue===a?S.displayValue:a,D=e=>{C({sourceValue:a,displayValue:e})},O=t(()=>`fullId-${x}`,[x]),k=t(()=>`halfId-${x}`,[x]),A=t(()=>`noneId-${x}`,[x]),j=e=>e.clientX-e.currentTarget.getBoundingClientRect().left>f/2,M=(e,t)=>u?j(e)?t:t-.5:t,N=(e,t)=>{l&&D(M(e,t))},P=()=>{l&&D(a||0)},F=()=>{c(E),T(!0)},I=(e,t)=>{if(!l)return;let n=M(e,t);D(n),c(n)},L=e=>{let t=E;t%1!=.5&&(t=Math.round(t)),t=Math.min(Math.max(t+e,0),d),D(t),_&&c(t)},R=e=>{switch(e.key){case`ArrowLeft`:L(u?-.5:-1);break;case`ArrowRight`:L(u?.5:1);break;case`Enter`:c(E)}},z=()=>Array.from({length:d},(e,t)=>{let n=t+1,i=n===d?void 0:{paddingRight:p};return r(`span`,{className:`star star-${n}`,style:i,children:r(o,{index:n,value:E,size:f,isHalf:u,fullId:O,halfId:k,noneId:A,primaryColor:h,secondaryColor:g,onMouseMove:e=>N(e,n),onMouseLeave:P,onChange:e=>I(e,n)})},`react-stars-rating-char${n}`)}),B=(l||_)&&!w,V=Math.min(Math.max(E,0),d);return r(`span`,{id:x,role:`slider`,"aria-label":y?void 0:v,"aria-labelledby":y,"aria-valuemin":0,"aria-valuemax":d,"aria-valuenow":V,"aria-valuetext":`${V} of ${d}`,tabIndex:B?0:-1,onKeyDown:B?R:void 0,onBlur:B?F:void 0,style:l?s.activeContainer:s.inActiveContainer,className:m,children:z()})};export{c as ReactStarsRating,c as default};
@@ -0,0 +1 @@
1
+ "use client";(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react")):typeof define==`function`&&define.amd?define([`exports`,`react`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ReactAwesomeStarsRating={},e.React))})(this,function(e,t){Object.defineProperties(e,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var n=({primaryColor:e,secondaryColor:t,offset:n=50,index:r,value:i,fullId:a,halfId:o,noneId:s})=>{let c=n;return r===1&&(c=Math.round(i%1*1e4)/100),r===1?React.createElement(`defs`,null,React.createElement(`linearGradient`,{id:a},React.createElement(`stop`,{offset:`100%`,stopColor:e})),React.createElement(`linearGradient`,{id:s},React.createElement(`stop`,{offset:`100%`,stopColor:t})),React.createElement(`linearGradient`,{id:o},React.createElement(`stop`,{offset:`${c}%`,stopColor:e}),React.createElement(`stop`,{offset:`${c}%`,stopColor:t}))):null},r=({viewBox:e=`0 0 306 306`,size:t,onMouseMove:r,onMouseLeave:i,onChange:a,index:o,value:s,isHalf:c,primaryColor:l,secondaryColor:u,fill:d,offset:f=50,fullId:p,halfId:m,noneId:h})=>{let g=d;return g=o<=s?`url(#${p})`:c&&Math.ceil(s)===o?`url(#${m})`:`url(#${h})`,React.createElement(`svg`,{width:t,viewBox:e,xmlns:`http://www.w3.org/2000/svg`,xmlnsXlink:`http://www.w3.org/1999/xlink`,onMouseLeave:i,onClick:a,onMouseMove:r},React.createElement(n,{primaryColor:l,secondaryColor:u,offset:f,index:o,value:s,fullId:p,halfId:m,noneId:h}),React.createElement(`polygon`,{fill:g,points:`153,230.775 247.35,299.625 211.65,187.425 306,121.125 191.25,121.125 153,6.375 114.75,121.125 0,121.125 94.35,187.425 58.65,299.625`,pointerEvents:`none`}))},i={activeContainer:{border:`none`,display:`inline-flex`},inActiveContainer:{border:`none`,outline:0,display:`inline-flex`}},a=({id:e,value:n=0,onChange:a=()=>{},isEdit:o=!0,isHalf:s=!0,count:c=5,size:l=25,starGap:u=0,className:d=``,primaryColor:f=`orange`,secondaryColor:p=`grey`,isArrowSubmit:m=!1,ariaLabel:h=`Star rating`,ariaLabelledBy:g})=>{let _=(0,t.useId)().replace(/:/g,``),v=e??`react-stars-rating-${_}`,[y,b]=(0,t.useState)(()=>({sourceValue:n,displayValue:n})),[x,S]=(0,t.useState)(!1),C=y.sourceValue===n?y.displayValue:n,w=e=>{b({sourceValue:n,displayValue:e})},T=(0,t.useMemo)(()=>`fullId-${v}`,[v]),E=(0,t.useMemo)(()=>`halfId-${v}`,[v]),D=(0,t.useMemo)(()=>`noneId-${v}`,[v]),O=e=>e.clientX-e.currentTarget.getBoundingClientRect().left>l/2,k=(e,t)=>s?O(e)?t:t-.5:t,A=(e,t)=>{o&&w(k(e,t))},j=()=>{o&&w(n||0)},M=()=>{a(C),S(!0)},N=(e,t)=>{if(!o)return;let n=k(e,t);w(n),a(n)},P=e=>{let t=C;t%1!=.5&&(t=Math.round(t)),t=Math.min(Math.max(t+e,0),c),w(t),m&&a(t)},F=e=>{switch(e.key){case`ArrowLeft`:P(s?-.5:-1);break;case`ArrowRight`:P(s?.5:1);break;case`Enter`:a(C)}},I=()=>Array.from({length:c},(e,t)=>{let n=t+1,i=n===c?void 0:{paddingRight:u};return React.createElement(`span`,{key:`react-stars-rating-char${n}`,className:`star star-${n}`,style:i},React.createElement(r,{index:n,value:C,size:l,isHalf:s,fullId:T,halfId:E,noneId:D,primaryColor:f,secondaryColor:p,onMouseMove:e=>A(e,n),onMouseLeave:j,onChange:e=>N(e,n)}))}),L=(o||m)&&!x,R=Math.min(Math.max(C,0),c);return React.createElement(`span`,{id:v,role:`slider`,"aria-label":g?void 0:h,"aria-labelledby":g,"aria-valuemin":0,"aria-valuemax":c,"aria-valuenow":R,"aria-valuetext":`${R} of ${c}`,tabIndex:L?0:-1,onKeyDown:L?F:void 0,onBlur:L?M:void 0,style:o?i.activeContainer:i.inActiveContainer,className:d},I())};e.ReactStarsRating=a,e.default=a});
package/dist/star.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { MouseEvent } from 'react';
2
+ type StarProps = {
3
+ viewBox?: string;
4
+ size: number;
5
+ primaryColor: string;
6
+ secondaryColor: string;
7
+ onMouseLeave?: (event: MouseEvent<SVGSVGElement>) => void;
8
+ onMouseMove?: (event: MouseEvent<SVGSVGElement>) => void;
9
+ onChange?: (event: MouseEvent<SVGSVGElement>) => void;
10
+ isHalf: boolean;
11
+ fill?: string;
12
+ index: number;
13
+ value: number;
14
+ offset?: number;
15
+ fullId: string;
16
+ halfId: string;
17
+ noneId: string;
18
+ };
19
+ declare const StarSVG: ({ viewBox, size, onMouseMove, onMouseLeave, onChange, index, value, isHalf, primaryColor, secondaryColor, fill, offset, fullId, halfId, noneId, }: StarProps) => import("react").JSX.Element;
20
+ export default StarSVG;
@@ -0,0 +1,12 @@
1
+ declare const styles: {
2
+ activeContainer: {
3
+ border: string;
4
+ display: string;
5
+ };
6
+ inActiveContainer: {
7
+ border: string;
8
+ outline: number;
9
+ display: string;
10
+ };
11
+ };
12
+ export default styles;
package/package.json CHANGED
@@ -1,89 +1,160 @@
1
1
  {
2
2
  "name": "react-awesome-stars-rating",
3
- "version": "0.16.2",
4
- "main": "./dist/index.js",
5
- "module": "./dist/index.js",
3
+ "version": "1.0.1",
4
+ "description": "Accessible star rating component for React, with half stars, keyboard control and any scale or palette.",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.mjs"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "unpkg": "./dist/index.umd.cjs",
22
+ "jsdelivr": "./dist/index.umd.cjs",
6
23
  "files": [
7
24
  "dist",
8
- "README.md"
25
+ "README.md",
26
+ "MIGRATION.md",
27
+ "LICENSE"
9
28
  ],
10
- "eslintConfig": {
11
- "extends": [
12
- "react-app",
13
- "eslint-config-prettier"
14
- ],
15
- "plugins": [
16
- "eslint-plugin-prettier"
17
- ],
18
- "rules": {
19
- "prettier/prettier": [
20
- "error"
21
- ]
22
- }
23
- },
24
- "browserslist": {
25
- "production": [
26
- ">0.2%",
27
- "not dead",
28
- "not op_mini all"
29
- ],
30
- "development": [
31
- "last 1 chrome version",
32
- "last 1 firefox version",
33
- "last 1 safari version"
34
- ]
35
- },
29
+ "sideEffects": false,
36
30
  "keywords": [
37
31
  "react",
38
- "awesome",
32
+ "react-component",
33
+ "star-rating",
34
+ "stars-rating",
35
+ "rating",
36
+ "rating-component",
39
37
  "stars",
40
38
  "star",
41
- "rating",
42
- "redux",
43
- "svg"
39
+ "half-star",
40
+ "review",
41
+ "feedback",
42
+ "accessibility",
43
+ "a11y",
44
+ "typescript",
45
+ "ui-component"
44
46
  ],
45
47
  "repository": {
46
48
  "type": "git",
47
- "url": "https://github.com/fedoryakubovich/react-awesome-stars-rating"
49
+ "url": "git+https://github.com/fedoryakubovich/react-awesome-stars-rating.git"
48
50
  },
51
+ "homepage": "https://react-awesome-stars-rating.vercel.app",
49
52
  "author": "Fedor Yakubovich",
50
53
  "bugs": {
51
54
  "url": "https://github.com/fedoryakubovich/react-awesome-stars-rating/issues"
52
55
  },
53
56
  "license": "MIT",
54
- "jest": {
55
- "collectCoverageFrom": [
56
- "src/lib/**/*.{js,jsx,ts,tsx}",
57
- "!src/lib/**/*.d.ts"
58
- ]
57
+ "engines": {
58
+ "node": ">=20"
59
59
  },
60
60
  "scripts": {
61
- "start": "react-scripts start",
62
- "build": "react-scripts build",
63
- "test": "react-scripts test",
64
- "eject": "react-scripts eject",
65
- "coverage": "react-scripts test --coverage --watchAll=false",
66
- "upload": "NODE_ENV=production babel src/lib --out-dir dist",
67
- "prepublishOnly": "npm run upload",
68
- "clean": "./node_modules/.bin/rimraf build/"
61
+ "dev": "vite",
62
+ "build": "vite build && vite build -c vite.umd.config.ts && tsc -p tsconfig.build.json && node scripts/emit-cjs-types.mjs",
63
+ "build:site": "vite build --config vite.site.config.ts",
64
+ "preview": "vite preview",
65
+ "lint": "eslint .",
66
+ "format": "prettier --check .",
67
+ "format:write": "prettier --write .",
68
+ "test": "vitest run",
69
+ "test:watch": "vitest",
70
+ "coverage": "vitest run --coverage",
71
+ "verify:package": "node scripts/verify-package.mjs",
72
+ "lint:package": "publint && attw --pack",
73
+ "size": "size-limit",
74
+ "typecheck": "tsc -p tsconfig.json --noEmit",
75
+ "commitlint": "commitlint",
76
+ "release": "semantic-release",
77
+ "prepack": "npm run build && npm run verify:package",
78
+ "prepare": "husky",
79
+ "storybook": "storybook dev -p 6006",
80
+ "build-storybook": "storybook build",
81
+ "clean": "rimraf dist dist-site"
69
82
  },
70
- "dependencies": {
71
- "prop-types": "^15.8.1",
72
- "react": "^17.0.2",
73
- "react-dom": "^17.0.2"
83
+ "peerDependencies": {
84
+ "react": ">=19",
85
+ "react-dom": ">=19"
74
86
  },
75
87
  "devDependencies": {
76
- "@babel/cli": "^7.23.9",
77
- "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
78
- "@testing-library/jest-dom": "^5.17.0",
79
- "@testing-library/react": "^12.1.5",
80
- "@testing-library/user-event": "^14.5.2",
81
- "eslint-config-prettier": "^8.10.0",
82
- "eslint-plugin-prettier": "^5.1.3",
83
- "prettier": "^3.2.5",
84
- "react-redux": "^7.2.9",
85
- "react-scripts": "5.0.1",
86
- "redux": "^4.2.1",
87
- "redux-form": "^8.3.10"
88
+ "@arethetypeswrong/cli": "^0.18.5",
89
+ "@commitlint/cli": "^21.2.2",
90
+ "@commitlint/config-conventional": "^21.2.2",
91
+ "@semantic-release/github": "^12.0.9",
92
+ "@semantic-release/npm": "^13.1.5",
93
+ "@size-limit/file": "^12.1.0",
94
+ "@storybook/addon-a11y": "^10.5.10",
95
+ "@storybook/addon-links": "^10.5.10",
96
+ "@storybook/react-vite": "^10.5.10",
97
+ "@tailwindcss/postcss": "^4.3.3",
98
+ "@tanstack/react-form": "^1.33.5",
99
+ "@testing-library/dom": "^10.4.1",
100
+ "@testing-library/jest-dom": "^7.0.1",
101
+ "@testing-library/react": "^16.3.3",
102
+ "@testing-library/user-event": "^14.6.6",
103
+ "@types/react": "^19.2.18",
104
+ "@types/react-dom": "^19.2.5",
105
+ "@typescript-eslint/eslint-plugin": "^8.68.0",
106
+ "@typescript-eslint/parser": "^8.68.0",
107
+ "@vitejs/plugin-react": "^6.1.1",
108
+ "@vitest/coverage-v8": "^4.1.11",
109
+ "axe-core": "^4.13.0",
110
+ "conventional-changelog-conventionalcommits": "^9.3.1",
111
+ "conventional-commits-filter": "^6.0.1",
112
+ "eslint": "^9.39.5",
113
+ "eslint-config-prettier": "^10.1.8",
114
+ "eslint-plugin-jsx-a11y": "^6.10.2",
115
+ "eslint-plugin-react": "^7.37.5",
116
+ "eslint-plugin-react-hooks": "^7.1.1",
117
+ "eslint-plugin-storybook": "10.5.10",
118
+ "formik": "^2.4.9",
119
+ "husky": "^9.1.7",
120
+ "jsdom": "^28.1.0",
121
+ "lint-staged": "^16.4.0",
122
+ "prettier": "^3.9.6",
123
+ "publint": "^0.3.24",
124
+ "react": "^19.2.8",
125
+ "react-dom": "^19.2.8",
126
+ "react-hook-form": "^7.86.0",
127
+ "rimraf": "^6.1.3",
128
+ "semantic-release": "^25.0.9",
129
+ "size-limit": "^12.1.0",
130
+ "storybook": "^10.5.10",
131
+ "tailwindcss": "^4.3.3",
132
+ "typescript": "^6.0.3",
133
+ "vite": "^8.2.2",
134
+ "vitest": "^4.1.11"
135
+ },
136
+ "size-limit": [
137
+ {
138
+ "name": "ESM entry",
139
+ "path": "dist/index.mjs",
140
+ "limit": "1.6 kB",
141
+ "gzip": true
142
+ },
143
+ {
144
+ "name": "CJS entry",
145
+ "path": "dist/index.cjs",
146
+ "limit": "1.65 kB",
147
+ "gzip": true
148
+ },
149
+ {
150
+ "name": "UMD bundle",
151
+ "path": "dist/index.umd.cjs",
152
+ "limit": "1.75 kB",
153
+ "gzip": true
154
+ }
155
+ ],
156
+ "lint-staged": {
157
+ "*.{ts,tsx,js,jsx,mjs,cjs,json,css,md}": "prettier --write",
158
+ "*.{ts,tsx,js,jsx,mjs}": "eslint --fix"
88
159
  }
89
160
  }
package/dist/gradient.js DELETED
@@ -1,53 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _react = _interopRequireDefault(require("react"));
8
- var _propTypes = _interopRequireDefault(require("prop-types"));
9
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10
- var Gradient = function Gradient(_ref) {
11
- var primaryColor = _ref.primaryColor,
12
- secondaryColor = _ref.secondaryColor,
13
- offset = _ref.offset,
14
- index = _ref.index,
15
- value = _ref.value,
16
- fullId = _ref.fullId,
17
- halfId = _ref.halfId,
18
- noneId = _ref.noneId;
19
- if (index === 1) {
20
- offset = value % 1 * 100;
21
- }
22
- return index === 1 && /*#__PURE__*/_react.default.createElement("defs", {
23
- "data-testid": "gradient",
24
- "data-offset": offset
25
- }, /*#__PURE__*/_react.default.createElement("linearGradient", {
26
- id: fullId
27
- }, /*#__PURE__*/_react.default.createElement("stop", {
28
- offset: "100%",
29
- stopColor: primaryColor
30
- })), /*#__PURE__*/_react.default.createElement("linearGradient", {
31
- id: noneId
32
- }, /*#__PURE__*/_react.default.createElement("stop", {
33
- offset: "100%",
34
- stopColor: secondaryColor
35
- })), /*#__PURE__*/_react.default.createElement("linearGradient", {
36
- id: halfId
37
- }, /*#__PURE__*/_react.default.createElement("stop", {
38
- offset: "".concat(offset, "%"),
39
- stopColor: primaryColor
40
- }), /*#__PURE__*/_react.default.createElement("stop", {
41
- offset: "".concat(offset, "%"),
42
- stopColor: secondaryColor
43
- })));
44
- };
45
- Gradient.propTypes = {
46
- primaryColor: _propTypes.default.string.isRequired,
47
- secondaryColor: _propTypes.default.string.isRequired,
48
- offset: _propTypes.default.number,
49
- index: _propTypes.default.number.isRequired,
50
- value: _propTypes.default.number.isRequired
51
- };
52
- var _default = Gradient;
53
- exports.default = _default;
package/dist/index.js DELETED
@@ -1,267 +0,0 @@
1
- "use strict";
2
-
3
- function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports.default = void 0;
8
- var _react = _interopRequireWildcard(require("react"));
9
- var _propTypes = _interopRequireDefault(require("prop-types"));
10
- var _star = _interopRequireDefault(require("./star"));
11
- var _styles = _interopRequireDefault(require("./styles"));
12
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
14
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
15
- function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
16
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
17
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
18
- function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
19
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
20
- function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
21
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
22
- function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
23
- function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
24
- function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); Object.defineProperty(subClass, "prototype", { writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }
25
- function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
26
- function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
27
- function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }
28
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
29
- function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
30
- function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
31
- var ReactStarsRating = /*#__PURE__*/function (_PureComponent) {
32
- _inherits(ReactStarsRating, _PureComponent);
33
- var _super = _createSuper(ReactStarsRating);
34
- function ReactStarsRating(props) {
35
- var _this;
36
- _classCallCheck(this, ReactStarsRating);
37
- _this = _super.call(this, props);
38
- _this.state = {
39
- value: props.value,
40
- isSubmitted: false
41
- };
42
- _this.onMouseMove = _this.onMouseMove.bind(_assertThisInitialized(_this));
43
- _this.onMouseLeave = _this.onMouseLeave.bind(_assertThisInitialized(_this));
44
- _this.onChange = _this.onChange.bind(_assertThisInitialized(_this));
45
- _this.onKeyDown = _this.onKeyDown.bind(_assertThisInitialized(_this));
46
- _this.onBlur = _this.onBlur.bind(_assertThisInitialized(_this));
47
- return _this;
48
- }
49
- _createClass(ReactStarsRating, [{
50
- key: "componentDidUpdate",
51
- value: function componentDidUpdate(prevProps) {
52
- if (this.props.value !== prevProps.value) {
53
- this.setState({
54
- value: this.props.value
55
- });
56
- }
57
- }
58
- }, {
59
- key: "isMoreThanHalf",
60
- value: function isMoreThanHalf(event) {
61
- var size = this.props.size;
62
- var point = event.clientX - event.target.getBoundingClientRect().left;
63
- return point > size / 2;
64
- }
65
- }, {
66
- key: "onMouseMove",
67
- value: function onMouseMove(event) {
68
- var isHalf = this.props.isHalf;
69
- var value = Number(event.target.getAttribute('data-stars'));
70
- if (isHalf) {
71
- var isMoreThanHalf = this.isMoreThanHalf(event);
72
- if (!isMoreThanHalf) {
73
- value -= 0.5;
74
- }
75
- }
76
- this.setState({
77
- value: value
78
- });
79
- }
80
- }, {
81
- key: "onMouseLeave",
82
- value: function onMouseLeave() {
83
- var value = this.props.value;
84
- this.setState({
85
- value: value || 0
86
- });
87
- }
88
- }, {
89
- key: "onBlur",
90
- value: function onBlur() {
91
- var onChange = this.props.onChange;
92
- var value = this.state.value;
93
- onChange(value);
94
- this.setState({
95
- isSubmitted: true
96
- });
97
- }
98
- }, {
99
- key: "onChange",
100
- value: function onChange(event) {
101
- var _this$props = this.props,
102
- onChange = _this$props.onChange,
103
- isHalf = _this$props.isHalf;
104
- var value = Number(event.target.getAttribute('data-stars'));
105
- if (isHalf) {
106
- var isMoreThanHalf = this.isMoreThanHalf(event);
107
- if (!isMoreThanHalf) {
108
- value -= 0.5;
109
- }
110
- }
111
- onChange(value);
112
- }
113
- }, {
114
- key: "onChangeStars",
115
- value: function onChangeStars(newValue) {
116
- var value = this.state.value;
117
- var count = this.props.count;
118
- if (value > 0 || value < count) {
119
- var _this$props2 = this.props,
120
- isArrowSubmit = _this$props2.isArrowSubmit,
121
- onChange = _this$props2.onChange;
122
- if (value > 0 && newValue < 0 || value < count && newValue > 0) {
123
- value = (value % 1 === 0.5 ? value : Math.round(value)) + newValue;
124
- }
125
- this.setState({
126
- value: value
127
- });
128
- if (isArrowSubmit) {
129
- onChange(value);
130
- }
131
- }
132
- }
133
- }, {
134
- key: "onKeyDown",
135
- value: function onKeyDown(event) {
136
- var keyCode = event.keyCode;
137
- var value = this.state.value;
138
- var _this$props3 = this.props,
139
- isHalf = _this$props3.isHalf,
140
- onChange = _this$props3.onChange;
141
- switch (keyCode) {
142
- case 37:
143
- this.onChangeStars(isHalf ? -0.5 : -1);
144
- break;
145
- case 39:
146
- this.onChangeStars(isHalf ? 0.5 : 1);
147
- break;
148
- case 13:
149
- onChange(value);
150
- break;
151
- default:
152
- break;
153
- }
154
- }
155
- }, {
156
- key: "renderStars",
157
- value: function renderStars() {
158
- var _this$props4 = this.props,
159
- count = _this$props4.count,
160
- size = _this$props4.size,
161
- isHalf = _this$props4.isHalf,
162
- isEdit = _this$props4.isEdit,
163
- primaryColor = _this$props4.primaryColor,
164
- secondaryColor = _this$props4.secondaryColor,
165
- starGap = _this$props4.starGap,
166
- id = _this$props4.id;
167
- var value = this.state.value;
168
- var starsList = [];
169
- var props = {
170
- primaryColor: primaryColor,
171
- secondaryColor: secondaryColor
172
- };
173
- var fullId = "fullId-".concat(id);
174
- var halfId = "halfId-".concat(id);
175
- var noneId = "noneId-".concat(id);
176
- if (isEdit) {
177
- props = _objectSpread(_objectSpread({}, props), {}, {
178
- onMouseMove: this.onMouseMove,
179
- onMouseLeave: this.onMouseLeave,
180
- onChange: this.onChange
181
- });
182
- }
183
- for (var i = 1; i <= count; i++) {
184
- var style = i !== count ? {
185
- paddingRight: starGap
186
- } : null;
187
- starsList.push( /*#__PURE__*/_react.default.createElement("span", {
188
- key: "react-stars-rating-char".concat(i),
189
- className: "star star-".concat(i),
190
- style: style,
191
- "data-testid": "star"
192
- }, /*#__PURE__*/_react.default.createElement(_star.default, _extends({
193
- index: i,
194
- value: value,
195
- size: size,
196
- isHalf: isHalf,
197
- fullId: fullId,
198
- halfId: halfId,
199
- noneId: noneId
200
- }, props))));
201
- }
202
- return starsList;
203
- }
204
- }, {
205
- key: "render",
206
- value: function render() {
207
- var _this$props5 = this.props,
208
- isEdit = _this$props5.isEdit,
209
- className = _this$props5.className,
210
- isArrowSubmit = _this$props5.isArrowSubmit,
211
- id = _this$props5.id;
212
- var stars = this.renderStars();
213
- var props = {
214
- tabIndex: -1
215
- };
216
- var isSubmitted = this.state.isSubmitted;
217
- if ((isEdit || isArrowSubmit) && !isSubmitted) {
218
- props = {
219
- onKeyDown: this.onKeyDown,
220
- onBlur: this.onBlur,
221
- tabIndex: 0
222
- };
223
- }
224
- return /*#__PURE__*/_react.default.createElement("span", _extends({
225
- id: id,
226
- role: "button"
227
- }, props, {
228
- style: isEdit ? _styles.default.activeContainer : _styles.default.inActiveContainer,
229
- className: className,
230
- "data-testid": "react-awesome-stars-rating",
231
- "data-value": this.state.value,
232
- "data-submitted": this.state.isSubmitted
233
- }), stars);
234
- }
235
- }]);
236
- return ReactStarsRating;
237
- }(_react.PureComponent);
238
- ReactStarsRating.propTypes = {
239
- onChange: _propTypes.default.func.isRequired,
240
- count: _propTypes.default.number.isRequired,
241
- value: _propTypes.default.number.isRequired,
242
- size: _propTypes.default.number.isRequired,
243
- primaryColor: _propTypes.default.string.isRequired,
244
- secondaryColor: _propTypes.default.string.isRequired,
245
- isEdit: _propTypes.default.bool.isRequired,
246
- isHalf: _propTypes.default.bool.isRequired,
247
- className: _propTypes.default.string.isRequired,
248
- starGap: _propTypes.default.number.isRequired,
249
- isArrowSubmit: _propTypes.default.bool.isRequired,
250
- id: _propTypes.default.string.isRequired
251
- };
252
- ReactStarsRating.defaultProps = {
253
- isEdit: true,
254
- isHalf: true,
255
- count: 5,
256
- value: 0,
257
- size: 25,
258
- primaryColor: 'orange',
259
- secondaryColor: 'grey',
260
- className: '',
261
- starGap: 0,
262
- isArrowSubmit: false,
263
- onChange: function onChange() {},
264
- id: "".concat(Date.now())
265
- };
266
- var _default = ReactStarsRating;
267
- exports.default = _default;
package/dist/star.js DELETED
@@ -1,78 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _react = _interopRequireDefault(require("react"));
8
- var _propTypes = _interopRequireDefault(require("prop-types"));
9
- var _gradient = _interopRequireDefault(require("./gradient"));
10
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
- var StarSVG = function StarSVG(_ref) {
12
- var viewBox = _ref.viewBox,
13
- size = _ref.size,
14
- onMouseMove = _ref.onMouseMove,
15
- onMouseLeave = _ref.onMouseLeave,
16
- onChange = _ref.onChange,
17
- index = _ref.index,
18
- value = _ref.value,
19
- isHalf = _ref.isHalf,
20
- primaryColor = _ref.primaryColor,
21
- secondaryColor = _ref.secondaryColor,
22
- fill = _ref.fill,
23
- offset = _ref.offset,
24
- fullId = _ref.fullId,
25
- halfId = _ref.halfId,
26
- noneId = _ref.noneId;
27
- if (index <= value) {
28
- fill = "url(#".concat(fullId, ")");
29
- } else if (isHalf && Math.ceil(value) === index) {
30
- fill = "url(#".concat(halfId, ")");
31
- } else {
32
- fill = "url(#".concat(noneId, ")");
33
- }
34
- var props = {
35
- primaryColor: primaryColor,
36
- secondaryColor: secondaryColor,
37
- offset: offset,
38
- index: index,
39
- value: value,
40
- fullId: fullId,
41
- halfId: halfId,
42
- noneId: noneId
43
- };
44
- return /*#__PURE__*/_react.default.createElement("svg", {
45
- width: size,
46
- viewBox: viewBox,
47
- xmlns: "http://www.w3.org/2000/svg",
48
- xmlnsXlink: "http://www.w3.org/1999/xlink",
49
- onMouseLeave: onMouseLeave,
50
- onClick: onChange,
51
- "data-stars": index,
52
- onMouseMove: onMouseMove
53
- }, /*#__PURE__*/_react.default.createElement(_gradient.default, props), /*#__PURE__*/_react.default.createElement("polygon", {
54
- fill: fill,
55
- points: "153,230.775 247.35,299.625 211.65,187.425 306,121.125 191.25,121.125 153,6.375 114.75,121.125 0,121.125 94.35,187.425 58.65,299.625",
56
- pointerEvents: "none"
57
- }));
58
- };
59
- StarSVG.propTypes = {
60
- viewBox: _propTypes.default.string,
61
- size: _propTypes.default.number.isRequired,
62
- primaryColor: _propTypes.default.string.isRequired,
63
- secondaryColor: _propTypes.default.string.isRequired,
64
- onMouseLeave: _propTypes.default.func,
65
- onMouseMove: _propTypes.default.func,
66
- onChange: _propTypes.default.func,
67
- isHalf: _propTypes.default.bool.isRequired,
68
- fill: _propTypes.default.string,
69
- index: _propTypes.default.number.isRequired,
70
- value: _propTypes.default.number.isRequired,
71
- offset: _propTypes.default.number.isRequired
72
- };
73
- StarSVG.defaultProps = {
74
- viewBox: '0 0 306 306',
75
- offset: 50
76
- };
77
- var _default = StarSVG;
78
- exports.default = _default;
package/dist/styles.js DELETED
@@ -1,17 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var styles = {
8
- activeContainer: {
9
- border: 'none'
10
- },
11
- inActiveContainer: {
12
- border: 'none',
13
- outline: 0
14
- }
15
- };
16
- var _default = styles;
17
- exports.default = _default;