@opengovsg/confetti 0.0.0 → 0.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/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # @opengovsg/confetti
2
+
3
+ Embeddable React survey widget for collecting user feedback.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@opengovsg/confetti.svg)](https://www.npmjs.com/package/@opengovsg/confetti)
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ # npm
11
+ npm install @opengovsg/confetti
12
+
13
+ # yarn
14
+ yarn add @opengovsg/confetti
15
+
16
+ # pnpm
17
+ pnpm add @opengovsg/confetti
18
+ ```
19
+
20
+ ### Peer Dependencies
21
+
22
+ This package requires React 18.2.0+ or React 19:
23
+
24
+ ```bash
25
+ npm install react@^18.2.0
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ 1. Import the CSS file in your application entry point:
31
+
32
+ ```tsx
33
+ import '@opengovsg/confetti/confetti.css'
34
+ ```
35
+
36
+ 2. Add the widget to your page:
37
+
38
+ ```tsx
39
+ import { PopoverConfetti } from '@opengovsg/confetti'
40
+
41
+ function App() {
42
+ return (
43
+ <div style={{ position: 'fixed', bottom: '1rem', right: '1rem' }}>
44
+ <PopoverConfetti
45
+ surveyId="your-survey-id"
46
+ publishableKey="your-publishable-key"
47
+ metadata={{}}
48
+ />
49
+ </div>
50
+ )
51
+ }
52
+ ```
53
+
54
+ > **Note:** You'll need the survey ID and publishable key from your Confetti dashboard. Make sure to whitelist your domain in your team settings.
55
+
56
+ 3. Add Confetti to your CSP headers:
57
+
58
+ ```
59
+ connect-src https://confetti.hack2026.gov.sg;
60
+ ```
61
+
62
+ ## Template Components
63
+
64
+ Choose the component that best fits your use case:
65
+
66
+ | Component | Use Case | Behavior |
67
+ | ------------------ | --------------------------------- | --------------------------------------------------------- |
68
+ | `EmbeddedConfetti` | Inline surveys, feedback sections | Shows questions in an inline manner with a submit button |
69
+ | `PopoverConfetti` | Floating feedback widgets | Dismissible popover, step-by-step questions, auto-submits |
70
+ | `StepperConfetti` | Guided surveys | One question at a time, auto-submits after last question |
71
+
72
+ ## Visibility Hooks
73
+
74
+ Control when your survey appears with these hooks:
75
+
76
+ ### useVisibleAfterDelay
77
+
78
+ Show the survey after a delay:
79
+
80
+ ```tsx
81
+ import { useVisibleAfterDelay } from '@opengovsg/confetti'
82
+
83
+ const { isVisible } = useVisibleAfterDelay({ delay: 5000 }) // 5 seconds
84
+ ```
85
+
86
+ ### useVisibleAfterScroll
87
+
88
+ Show the survey after scrolling a certain distance:
89
+
90
+ ```tsx
91
+ import { useVisibleAfterScroll } from '@opengovsg/confetti'
92
+
93
+ const { isVisible } = useVisibleAfterScroll({ threshold: 500 }) // 500px
94
+ ```
@@ -10,6 +10,7 @@
10
10
  --confetti-border-bottom: 1.5px solid var(--confetti-border-color);
11
11
  --confetti-border-radius: 12px;
12
12
  --confetti-background-color: #ffffff;
13
+ --confetti-hover-background-color: #f5f5f5;
13
14
  --confetti-box-shadow:
14
15
  0 4px 6px -4px rgba(16, 24, 40, 0.1), 0 10px 15px -3px rgba(0, 0, 0, 0.1);
15
16
  --confetti-focus-shadow: 0 0 0 2px rgba(9, 9, 11, 0.3);
@@ -38,6 +39,7 @@
38
39
  }
39
40
 
40
41
  .confetti-dialog {
42
+ max-width: var(--confetti-max-width);
41
43
  background: transparent;
42
44
  position: relative;
43
45
 
@@ -87,7 +89,6 @@
87
89
  color: var(--confetti-text-primary-color);
88
90
  font-size: 16px;
89
91
  width: 100%;
90
- max-width: var(--confetti-max-width);
91
92
  background: var(--confetti-background-color);
92
93
 
93
94
  box-shadow: var(--confetti-box-shadow);
@@ -104,9 +105,7 @@
104
105
  font-weight: 500;
105
106
  line-height: 20px;
106
107
 
107
- &:hover {
108
- transform: scale(1.05);
109
- }
108
+ transition: background 200ms ease-out;
110
109
 
111
110
  &:focus-visible {
112
111
  outline: 2px solid var(--confetti-outline-color);
@@ -118,6 +117,22 @@
118
117
  cursor: not-allowed;
119
118
  transform: none;
120
119
  }
120
+
121
+ &:hover {
122
+ background: color-mix(
123
+ in srgb,
124
+ white 10%,
125
+ var(--confetti-submit-button-color)
126
+ );
127
+ }
128
+
129
+ &:active {
130
+ background: color-mix(
131
+ in srgb,
132
+ white 5%,
133
+ var(--confetti-submit-button-color)
134
+ );
135
+ }
121
136
  }
122
137
 
123
138
  .sr-only {
@@ -138,13 +153,40 @@
138
153
  gap: 12px;
139
154
  }
140
155
 
156
+ .cf-choice {
157
+ font-size: 16px;
158
+ cursor: pointer;
159
+ padding: 8px 10px;
160
+ border-radius: 6px;
161
+ border: 1px solid var(--confetti-border-color);
162
+
163
+ transition: background 200ms ease-out;
164
+
165
+ &:hover {
166
+ background: var(--confetti-hover-background-color);
167
+ }
168
+
169
+ .cf-choice-label {
170
+ gap: 8px;
171
+ display: inline-flex;
172
+ align-items: center;
173
+ }
174
+
175
+ .cf-choice-description {
176
+ font-size: 0.875em;
177
+ margin-left: 26px;
178
+ color: var(--confetti-text-subtle-color);
179
+ }
180
+ }
181
+
141
182
  .cf-radio,
142
183
  .cf-checkbox {
184
+ cursor: pointer;
143
185
  display: flex;
186
+ flex-direction: column;
144
187
  /* This is needed so the hidden input is positioned correctly */
145
188
  position: relative;
146
- align-items: center;
147
- gap: 8px;
189
+ align-items: start;
148
190
  color: var(--confetti-text-primary-color);
149
191
  forced-color-adjust: none;
150
192
  }
@@ -153,7 +195,7 @@
153
195
  --checkmark-color: var(--confetti-indicator-active-dot-color);
154
196
 
155
197
  .cf-checkbox-indicator {
156
- background: var(--confetti-input-background);
198
+ background: white;
157
199
  border: 1px solid var(--confetti-border-color);
158
200
  width: 18px;
159
201
  height: 18px;
@@ -217,6 +259,7 @@
217
259
  border-radius: 50%;
218
260
  transition: color 200ms ease-out;
219
261
  border: 1px solid var(--confetti-border-color);
262
+ background: white;
220
263
 
221
264
  &::after {
222
265
  content: '';
@@ -303,7 +346,7 @@
303
346
  .cf-others-choice {
304
347
  display: flex;
305
348
  flex-direction: column;
306
- gap: 4px;
349
+ gap: 8px;
307
350
  }
308
351
  }
309
352
 
package/build/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import * as react0 from "react";
2
2
  import { HTMLAttributes, PropsWithChildren } from "react";
3
3
  import { z } from "zod/v4/mini";
4
- import * as react_jsx_runtime1 from "react/jsx-runtime";
4
+ import * as react_jsx_runtime3 from "react/jsx-runtime";
5
5
 
6
6
  //#region ../validators/src/questions/properties.d.ts
7
+
7
8
  declare const ratingQuestionSchema: z.ZodMiniObject<{
8
9
  type: z.ZodMiniLiteral<"rating">;
9
10
  scale: z.ZodMiniNumber<number>;
@@ -22,24 +23,26 @@ type TextQuestion = z.infer<typeof textQuestionSchema>;
22
23
  declare const singleSelectQuestionSchema: z.ZodMiniObject<{
23
24
  type: z.ZodMiniLiteral<"single-select">;
24
25
  options: z.ZodMiniArray<z.ZodMiniObject<{
25
- label: z.ZodMiniString<string>;
26
26
  value: z.ZodMiniString<string>;
27
+ description: z.ZodMiniOptional<z.ZodMiniString<string>>;
27
28
  }, z.core.$strip>>;
28
29
  editable: z.ZodMiniNullable<z.ZodMiniObject<{
29
30
  label: z.ZodMiniString<string>;
30
31
  max: z.ZodMiniNumber<number>;
32
+ description: z.ZodMiniOptional<z.ZodMiniString<string>>;
31
33
  }, z.core.$strip>>;
32
34
  }, z.core.$strip>;
33
35
  type SingleSelectQuestion = z.infer<typeof singleSelectQuestionSchema>;
34
36
  declare const multiSelectQuestionSchema: z.ZodMiniObject<{
35
37
  type: z.ZodMiniLiteral<"multi-select">;
36
38
  options: z.ZodMiniArray<z.ZodMiniObject<{
37
- label: z.ZodMiniString<string>;
38
39
  value: z.ZodMiniString<string>;
40
+ description: z.ZodMiniOptional<z.ZodMiniString<string>>;
39
41
  }, z.core.$strip>>;
40
42
  editable: z.ZodMiniNullable<z.ZodMiniObject<{
41
43
  label: z.ZodMiniString<string>;
42
44
  max: z.ZodMiniNumber<number>;
45
+ description: z.ZodMiniOptional<z.ZodMiniString<string>>;
43
46
  }, z.core.$strip>>;
44
47
  max: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
45
48
  }, z.core.$strip>;
@@ -66,12 +69,13 @@ declare const publicGetSurveyOutputSchema: z.ZodMiniObject<{
66
69
  }, z.core.$strip>, z.ZodMiniObject<{
67
70
  type: z.ZodMiniLiteral<"single-select">;
68
71
  options: z.ZodMiniArray<z.ZodMiniObject<{
69
- label: z.ZodMiniString<string>;
70
72
  value: z.ZodMiniString<string>;
73
+ description: z.ZodMiniOptional<z.ZodMiniString<string>>;
71
74
  }, z.core.$strip>>;
72
75
  editable: z.ZodMiniNullable<z.ZodMiniObject<{
73
76
  label: z.ZodMiniString<string>;
74
77
  max: z.ZodMiniNumber<number>;
78
+ description: z.ZodMiniOptional<z.ZodMiniString<string>>;
75
79
  }, z.core.$strip>>;
76
80
  }, z.core.$strip>, z.ZodMiniObject<{
77
81
  type: z.ZodMiniLiteral<"open-ended">;
@@ -79,12 +83,13 @@ declare const publicGetSurveyOutputSchema: z.ZodMiniObject<{
79
83
  }, z.core.$strip>, z.ZodMiniObject<{
80
84
  type: z.ZodMiniLiteral<"multi-select">;
81
85
  options: z.ZodMiniArray<z.ZodMiniObject<{
82
- label: z.ZodMiniString<string>;
83
86
  value: z.ZodMiniString<string>;
87
+ description: z.ZodMiniOptional<z.ZodMiniString<string>>;
84
88
  }, z.core.$strip>>;
85
89
  editable: z.ZodMiniNullable<z.ZodMiniObject<{
86
90
  label: z.ZodMiniString<string>;
87
91
  max: z.ZodMiniNumber<number>;
92
+ description: z.ZodMiniOptional<z.ZodMiniString<string>>;
88
93
  }, z.core.$strip>>;
89
94
  max: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
90
95
  }, z.core.$strip>], "type">;
@@ -129,14 +134,14 @@ declare const publicGetSurveyOutputSchema: z.ZodMiniObject<{
129
134
  }, z.core.$strip>;
130
135
  type PublicGetSurveyOutput = z.infer<typeof publicGetSurveyOutputSchema>;
131
136
  //#endregion
132
- //#region src/types/index.d.ts
133
- type Question$1 = {
137
+ //#region src/core/types.d.ts
138
+ type Question = {
134
139
  visible: boolean;
135
140
  error?: string;
136
141
  } & PublicGetSurveyOutput['questions'][number];
137
142
  type Answer = string | number | string[] | undefined;
138
143
  interface ConfettiState {
139
- questions: Question$1[];
144
+ questions: Question[];
140
145
  current: number;
141
146
  update: ({
142
147
  question,
@@ -151,10 +156,10 @@ interface ConfettiState {
151
156
  submit: () => void;
152
157
  isCompleted: boolean;
153
158
  isSubmitted: boolean;
154
- errors: Record<Question$1['id'], string>;
159
+ errors: Record<Question['id'], string>;
155
160
  }
156
161
  //#endregion
157
- //#region src/components/ConfettiController.d.ts
162
+ //#region src/core/ConfettiController.d.ts
158
163
  interface ConfettiControllerProps {
159
164
  children: (props: ConfettiState) => React.ReactElement;
160
165
  /**
@@ -170,16 +175,16 @@ declare const ConfettiController: ({
170
175
  shouldAutoSubmit,
171
176
  onFinished,
172
177
  children
173
- }: ConfettiControllerProps) => react_jsx_runtime1.JSX.Element;
178
+ }: ConfettiControllerProps) => react_jsx_runtime3.JSX.Element;
174
179
  //#endregion
175
- //#region src/components/ConfettiProvider.d.ts
180
+ //#region src/core/ConfettiProvider.d.ts
176
181
  interface ConfettiContextValue {
177
182
  surveyId: string;
178
183
  metadata: Record<string, string>;
179
184
  submit: ({
180
185
  answers
181
186
  }: {
182
- answers: Record<Question$1['id'], Answer>;
187
+ answers: Record<Question['id'], Answer>;
183
188
  }) => Promise<void>;
184
189
  dismiss: () => Promise<void> | void;
185
190
  survey: PublicGetSurveyOutput | undefined;
@@ -204,7 +209,7 @@ declare const ConfettiProvider: ({
204
209
  metadata,
205
210
  isSurveyVisible: isSurveyVisibleInput,
206
211
  apiBaseUrl
207
- }: ConfettiProviderProps) => react_jsx_runtime1.JSX.Element | null;
212
+ }: ConfettiProviderProps) => react_jsx_runtime3.JSX.Element | null;
208
213
  declare const useConfetti: () => ConfettiContextValue;
209
214
  //#endregion
210
215
  //#region src/components/Confetti.d.ts
@@ -213,7 +218,7 @@ declare const Confetti: ({
213
218
  children,
214
219
  shouldAutoSubmit,
215
220
  ...props
216
- }: ConfettiProps & Pick<ConfettiControllerProps, "children" | "shouldAutoSubmit">) => react_jsx_runtime1.JSX.Element;
221
+ }: ConfettiProps & Pick<ConfettiControllerProps, "children" | "shouldAutoSubmit">) => react_jsx_runtime3.JSX.Element;
217
222
  //#endregion
218
223
  //#region src/components/ThankYouMessage.d.ts
219
224
  interface ThankYouMessageProps {
@@ -230,7 +235,7 @@ declare const ThankYouMessage: ({
230
235
  title,
231
236
  description,
232
237
  classNames
233
- }: ThankYouMessageProps) => react_jsx_runtime1.JSX.Element;
238
+ }: ThankYouMessageProps) => react_jsx_runtime3.JSX.Element;
234
239
  //#endregion
235
240
  //#region src/components/container/PopoverContainer.d.ts
236
241
  interface PopoverContainerProps {
@@ -252,10 +257,10 @@ declare const PopoverContainer: ({
252
257
  containerProps,
253
258
  onDismiss,
254
259
  closeOnFinishMs
255
- }: PopoverContainerProps) => react_jsx_runtime1.JSX.Element;
260
+ }: PopoverContainerProps) => react_jsx_runtime3.JSX.Element;
256
261
  //#endregion
257
262
  //#region src/components/questions/types.d.ts
258
- type Question = PublicGetSurveyOutput['questions'][number];
263
+ type Question$1 = PublicGetSurveyOutput['questions'][number];
259
264
  interface BaseFieldProps {
260
265
  id: string;
261
266
  title: string | null | undefined;
@@ -267,7 +272,7 @@ interface BaseFieldProps {
267
272
  //#endregion
268
273
  //#region src/components/questions/factory.d.ts
269
274
  interface SurveyQuestionFactoryProps {
270
- question: Question;
275
+ question: Question$1;
271
276
  onChange: (answer: Answer) => void;
272
277
  error?: string;
273
278
  }
@@ -275,7 +280,7 @@ declare const SurveyQuestionFactory: ({
275
280
  question,
276
281
  onChange,
277
282
  error
278
- }: SurveyQuestionFactoryProps) => react_jsx_runtime1.JSX.Element;
283
+ }: SurveyQuestionFactoryProps) => react_jsx_runtime3.JSX.Element;
279
284
  //#endregion
280
285
  //#region src/components/questions/Rating.d.ts
281
286
  interface RatingProps extends BaseFieldProps {
@@ -308,7 +313,7 @@ declare const Rating: ({
308
313
  id,
309
314
  error,
310
315
  required
311
- }: RatingProps) => react_jsx_runtime1.JSX.Element;
316
+ }: RatingProps) => react_jsx_runtime3.JSX.Element;
312
317
  //#endregion
313
318
  //#region src/components/questions/FreeText.d.ts
314
319
  interface FreeTextProps extends BaseFieldProps {
@@ -331,7 +336,7 @@ declare const FreeText: ({
331
336
  classNames,
332
337
  required,
333
338
  error
334
- }: FreeTextProps) => react_jsx_runtime1.JSX.Element;
339
+ }: FreeTextProps) => react_jsx_runtime3.JSX.Element;
335
340
  //#endregion
336
341
  //#region src/components/questions/SingleChoice.d.ts
337
342
  interface SingleChoiceProps extends BaseFieldProps {
@@ -339,6 +344,7 @@ interface SingleChoiceProps extends BaseFieldProps {
339
344
  classNames?: {
340
345
  question?: string;
341
346
  header?: string;
347
+ label?: string;
342
348
  title?: string;
343
349
  description?: string;
344
350
  group?: string;
@@ -346,6 +352,7 @@ interface SingleChoiceProps extends BaseFieldProps {
346
352
  indicator?: string;
347
353
  othersChoice?: string;
348
354
  othersInput?: string;
355
+ choiceDescription?: string;
349
356
  error?: string;
350
357
  };
351
358
  }
@@ -358,7 +365,7 @@ declare const SingleChoice: ({
358
365
  id,
359
366
  required,
360
367
  error
361
- }: SingleChoiceProps) => react_jsx_runtime1.JSX.Element;
368
+ }: SingleChoiceProps) => react_jsx_runtime3.JSX.Element;
362
369
  //#endregion
363
370
  //#region src/components/questions/MultiChoice.d.ts
364
371
  interface MultiChoiceProps extends BaseFieldProps {
@@ -366,8 +373,10 @@ interface MultiChoiceProps extends BaseFieldProps {
366
373
  classNames?: {
367
374
  question?: string;
368
375
  header?: string;
376
+ label?: string;
369
377
  title?: string;
370
378
  description?: string;
379
+ choiceDescription?: string;
371
380
  group?: string;
372
381
  checkbox?: string;
373
382
  indicator?: string;
@@ -386,26 +395,26 @@ declare const MultiChoice: ({
386
395
  id,
387
396
  required,
388
397
  error
389
- }: MultiChoiceProps) => react_jsx_runtime1.JSX.Element;
398
+ }: MultiChoiceProps) => react_jsx_runtime3.JSX.Element;
390
399
  //#endregion
391
400
  //#region src/components/presentation/Flow.d.ts
392
401
  type ChildField = ({
393
402
  onChange
394
403
  }: {
395
404
  onChange: (answer: Answer) => void;
396
- question: Question;
405
+ question: Question$1;
397
406
  error?: string;
398
407
  }) => React.ReactNode;
399
408
  interface FlowProps {
400
409
  onSubmit: (answer: Answer) => void;
401
410
  children: ChildField;
402
- question: Question;
411
+ question: Question$1;
403
412
  }
404
413
  declare const Flow: ({
405
414
  onSubmit,
406
415
  children,
407
416
  question
408
- }: FlowProps) => react_jsx_runtime1.JSX.Element;
417
+ }: FlowProps) => react_jsx_runtime3.JSX.Element;
409
418
  //#endregion
410
419
  //#region src/components/presentation/Embed.d.ts
411
420
  declare const Embed: ({
@@ -415,13 +424,62 @@ declare const Embed: ({
415
424
  }: PropsWithChildren<{
416
425
  isCompleted: boolean;
417
426
  onSubmit: () => void;
418
- }>) => react_jsx_runtime1.JSX.Element;
427
+ }>) => react_jsx_runtime3.JSX.Element;
419
428
  //#endregion
420
429
  //#region src/templates/EmbeddedConfetti.d.ts
421
- declare const EmbeddedConfetti: (props: ConfettiProps) => react_jsx_runtime1.JSX.Element;
430
+ declare const EmbeddedConfetti: (props: ConfettiProps) => react_jsx_runtime3.JSX.Element;
431
+ //#endregion
432
+ //#region src/templates/PopoverConfetti.d.ts
433
+ interface PopoverConfettiProps extends ConfettiProps {
434
+ closeOnFinishMs?: number;
435
+ }
436
+ declare const PopoverConfetti: ({
437
+ closeOnFinishMs,
438
+ ...props
439
+ }: PopoverConfettiProps) => react_jsx_runtime3.JSX.Element;
422
440
  //#endregion
423
441
  //#region src/templates/StepperConfetti.d.ts
424
- declare const StepperConfetti: (props: ConfettiProps) => react_jsx_runtime1.JSX.Element;
442
+ declare const StepperConfetti: (props: ConfettiProps) => react_jsx_runtime3.JSX.Element;
443
+ //#endregion
444
+ //#region src/hooks/useVisibleAfterDelay.d.ts
445
+ interface UseVisibleAfterDelayOptions {
446
+ delay: number;
447
+ }
448
+ declare const useVisibleAfterDelay: ({
449
+ delay
450
+ }: UseVisibleAfterDelayOptions) => {
451
+ isVisible: boolean;
452
+ };
453
+ //#endregion
454
+ //#region src/hooks/useVisibleAfterPageVisits.d.ts
455
+ interface UseVisibleAfterPageVisitsOptions {
456
+ visits: number;
457
+ respondent?: string;
458
+ }
459
+ declare const useVisibleAfterPageVisits: ({
460
+ visits,
461
+ respondent
462
+ }: UseVisibleAfterPageVisitsOptions) => {
463
+ isVisible: boolean;
464
+ reset: () => void;
465
+ };
466
+ declare const useVisibleAfterSessionPageVisits: ({
467
+ visits,
468
+ respondent
469
+ }: UseVisibleAfterPageVisitsOptions) => {
470
+ isVisible: boolean;
471
+ reset: () => void;
472
+ };
473
+ //#endregion
474
+ //#region src/hooks/useVisibleAfterScroll.d.ts
475
+ interface UseVisibleAfterScrollOptions {
476
+ threshold: number;
477
+ }
478
+ declare const useVisibleAfterScroll: ({
479
+ threshold
480
+ }: UseVisibleAfterScrollOptions) => {
481
+ isVisible: boolean;
482
+ };
425
483
  //#endregion
426
- export { Confetti, ConfettiContext, ConfettiController, type ConfettiControllerProps, type ConfettiProps, ConfettiProvider, type ConfettiProviderProps, Embed, EmbeddedConfetti, Flow, FreeText, type FreeTextProps, MultiChoice, type MultiChoiceProps, PopoverContainer, type PopoverContainerProps, Rating, type RatingProps, SingleChoice, type SingleChoiceProps, StepperConfetti, SurveyQuestionFactory, type SurveyQuestionFactoryProps, ThankYouMessage, useConfetti };
484
+ export { type Answer, Confetti, ConfettiContext, ConfettiController, type ConfettiControllerProps, type ConfettiProps, ConfettiProvider, type ConfettiProviderProps, type ConfettiState, Embed, EmbeddedConfetti, Flow, FreeText, type FreeTextProps, MultiChoice, type MultiChoiceProps, PopoverConfetti, PopoverContainer, type PopoverContainerProps, type Question, Rating, type RatingProps, SingleChoice, type SingleChoiceProps, StepperConfetti, SurveyQuestionFactory, type SurveyQuestionFactoryProps, ThankYouMessage, useConfetti, useVisibleAfterDelay, useVisibleAfterPageVisits, useVisibleAfterScroll, useVisibleAfterSessionPageVisits };
427
485
  //# sourceMappingURL=index.d.ts.map
package/build/index.js CHANGED
@@ -1,67 +1,16 @@
1
1
  import { ErrorBoundary } from "react-error-boundary";
2
2
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
3
+ import { useLocalStorage, useSessionStorage, useTimeout } from "usehooks-ts";
3
4
  import { z } from "zod/v4/mini";
4
- import { useLocalStorage, useTimeout } from "usehooks-ts";
5
5
  import ky from "ky";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
7
  import clsx from "clsx";
8
8
  import { Button, Checkbox, CheckboxGroup, FieldError, Input, Label, Radio, RadioGroup, Text, TextArea, TextField, composeRenderProps } from "react-aria-components";
9
9
 
10
- //#region src/logic/route.ts
11
- const isVisible = ({ index, questions, answers }) => {
12
- if (index === 0) return true;
13
- for (let i = 0; i < index; i++) {
14
- const question = questions[i];
15
- const answer = question ? answers[question.id] : void 0;
16
- if (!question || !question.visible) continue;
17
- const logic = question.routingLogic;
18
- if (logic.type === "always") if (evaluateTarget({
19
- position: i,
20
- value: logic.target
21
- }) === index) return true;
22
- else continue;
23
- if ((answer === void 0 || answer === null) && question.required) continue;
24
- const cases = logic.cases;
25
- const match = answer !== null ? cases.find((condition) => evaluateCondition({
26
- answer,
27
- condition
28
- })) : void 0;
29
- if (!match) if (evaluateTarget({
30
- position: i,
31
- value: logic.default
32
- }) === index) return true;
33
- else continue;
34
- if (evaluateTarget({
35
- position: i,
36
- value: match.target
37
- }) === index) return true;
38
- else continue;
39
- }
40
- return false;
41
- };
42
- const evaluateTarget = ({ position, value }) => {
43
- switch (value.type) {
44
- case "next": return position + 1;
45
- case "jump": return value.target;
46
- case "end": return null;
47
- }
48
- };
49
- const evaluateCondition = ({ answer, condition }) => {
50
- const value = evaluateValue(condition.value);
51
- switch (condition.operator) {
52
- case "equal": return answer === value;
53
- case "not-equal": return answer !== value;
54
- case "greater": return typeof answer === "number" && typeof value === "number" && answer > value;
55
- case "greater-or-equal": return typeof answer === "number" && typeof value === "number" && answer >= value;
56
- case "less": return typeof answer === "number" && typeof value === "number" && answer < value;
57
- case "less-or-equal": return typeof answer === "number" && typeof value === "number" && answer <= value;
58
- case "contains": return Array.isArray(answer) && typeof value === "string" && answer.includes(value);
59
- case "not-contains": return Array.isArray(answer) && typeof value === "string" && !answer.includes(value);
60
- }
61
- };
62
- const evaluateValue = (node) => {
63
- return node.value;
64
- };
10
+ //#region src/utils.ts
11
+ function prettifyError(error) {
12
+ return error.issues[0]?.message ?? "Invalid input";
13
+ }
65
14
 
66
15
  //#endregion
67
16
  //#region ../validators/src/questions/routing.ts
@@ -109,12 +58,13 @@ const routingLogicSchema = z.discriminatedUnion("type", [alwaysConditionSchema,
109
58
  //#endregion
110
59
  //#region ../validators/src/questions/properties.ts
111
60
  const optionSchema = z.object({
112
- label: z.string().check(z.trim(), z.minLength(1, { error: "Label is required" })),
113
- value: z.string().check(z.trim(), z.minLength(1, { error: "Value is required" }))
61
+ value: z.string().check(z.trim(), z.minLength(1, { error: "Value is required" })),
62
+ description: z.optional(z.string().check(z.trim()))
114
63
  });
115
64
  const editableSchema = z.nullable(z.object({
116
- label: z.string().check(z.trim(), z.minLength(1, { error: "Label is required" })),
117
- max: z.number()
65
+ label: z.string().check(z.trim(), z.minLength(1, { error: "Value is required" })),
66
+ max: z.number(),
67
+ description: z.optional(z.string().check(z.trim()))
118
68
  }));
119
69
  const ratingQuestionSchema = z.object({
120
70
  type: z.literal("rating"),
@@ -201,48 +151,8 @@ const publicPutResponseInputSchema = z.object({
201
151
  const publicGetRespondentOutputSchema = z.object({ lastRespondedAt: z.nullable(z.union([z.iso.datetime(), z.date()])) });
202
152
 
203
153
  //#endregion
204
- //#region src/logic/validate.ts
205
- const VALIDATOR_FACTORY_MAP = {
206
- rating: ({ scale }, meta) => ratingAnswerSchemaFactory({ scale }, meta),
207
- "open-ended": ({ max }, meta) => openEndedAnswerSchemaFactory({ maxLength: max }, meta),
208
- "single-select": ({ editable }, meta) => singleSelectAnswerSchemaFactory({ maxLength: editable?.max }, meta),
209
- "multi-select": ({ editable, max }, meta) => multiSelectAnswerSchemaFactory({
210
- maxLength: editable?.max,
211
- maxSelected: max
212
- }, meta)
213
- };
214
- const getAnswerValidator = (properties, meta) => {
215
- const type = properties.type;
216
- switch (type) {
217
- case "rating": {
218
- const validator = VALIDATOR_FACTORY_MAP[type];
219
- return validator(properties, meta);
220
- }
221
- case "open-ended": {
222
- const validator = VALIDATOR_FACTORY_MAP[type];
223
- return validator(properties, meta);
224
- }
225
- case "single-select": {
226
- const validator = VALIDATOR_FACTORY_MAP[type];
227
- return validator(properties, meta);
228
- }
229
- case "multi-select": {
230
- const validator = VALIDATOR_FACTORY_MAP[type];
231
- return validator(properties, meta);
232
- }
233
- default: throw new Error("Unsupported question type");
234
- }
235
- };
236
-
237
- //#endregion
238
- //#region src/utils.ts
239
- function prettifyError(error) {
240
- return error.issues[0]?.message ?? "Invalid input";
241
- }
242
-
243
- //#endregion
244
- //#region src/logic/api.ts
245
- const API_HOST = "https://confetti.hack2026.gov.sg/api/cfti";
154
+ //#region src/core/logic/api.ts
155
+ const API_HOST = "https://confetti.hack2026.gov.sg/api";
246
156
  const client = ky.create({
247
157
  prefixUrl: API_HOST,
248
158
  retry: {
@@ -253,7 +163,7 @@ const client = ky.create({
253
163
  });
254
164
 
255
165
  //#endregion
256
- //#region src/components/ConfettiProvider.tsx
166
+ //#region src/core/ConfettiProvider.tsx
257
167
  const ConfettiContext = createContext(null);
258
168
  const ConfettiProvider = ({ children, surveyId, publishableKey, respondent, metadata, isSurveyVisible: isSurveyVisibleInput, apiBaseUrl }) => {
259
169
  const [survey, setSurvey] = useState();
@@ -270,13 +180,13 @@ const ConfettiProvider = ({ children, surveyId, publishableKey, respondent, meta
270
180
  return client.extend(properties);
271
181
  }, [apiBaseUrl, publishableKey]);
272
182
  useEffect(() => {
273
- client$1.get(`${surveyId}`).json().then((data) => {
183
+ client$1.get(`v1/cfti/${surveyId}`).json().then((data) => {
274
184
  const parseResult = publicGetSurveyOutputSchema.safeParse(data);
275
185
  if (!parseResult.success) return;
276
186
  setSurvey(parseResult.data);
277
187
  });
278
188
  if (!respondent && !internalRespondentId) return;
279
- client$1.get(`${surveyId}/respondent/${respondent ?? internalRespondentId}`).json().then((data) => {
189
+ client$1.get(`v1/cfti/${surveyId}/respondent/${respondent ?? internalRespondentId}`).json().then((data) => {
280
190
  const parseResult = publicGetRespondentOutputSchema.safeParse(data);
281
191
  if (!parseResult.success) {
282
192
  setLastRespondedAt(null);
@@ -292,7 +202,7 @@ const ConfettiProvider = ({ children, surveyId, publishableKey, respondent, meta
292
202
  surveyId
293
203
  ]);
294
204
  const submit = useCallback(async ({ answers }) => {
295
- await client$1.put(`${surveyId}/response/${responseId}`, { json: {
205
+ await client$1.put(`v1/cfti/${surveyId}/response/${responseId}`, { json: {
296
206
  respondent: respondent ?? internalRespondentId,
297
207
  data: answers,
298
208
  metadata
@@ -332,7 +242,98 @@ const useConfetti = () => {
332
242
  };
333
243
 
334
244
  //#endregion
335
- //#region src/components/ConfettiController.tsx
245
+ //#region src/core/logic/route.ts
246
+ const isVisible = ({ index, questions, answers }) => {
247
+ if (index === 0) return true;
248
+ for (let i = 0; i < index; i++) {
249
+ const question = questions[i];
250
+ const answer = question ? answers[question.id] : void 0;
251
+ if (!question || !question.visible) continue;
252
+ const logic = question.routingLogic;
253
+ if (logic.type === "always") if (evaluateTarget({
254
+ position: i,
255
+ value: logic.target
256
+ }) === index) return true;
257
+ else continue;
258
+ if ((answer === void 0 || answer === null) && question.required) continue;
259
+ const cases = logic.cases;
260
+ const match = answer !== null ? cases.find((condition) => evaluateCondition({
261
+ answer,
262
+ condition
263
+ })) : void 0;
264
+ if (!match) if (evaluateTarget({
265
+ position: i,
266
+ value: logic.default
267
+ }) === index) return true;
268
+ else continue;
269
+ if (evaluateTarget({
270
+ position: i,
271
+ value: match.target
272
+ }) === index) return true;
273
+ else continue;
274
+ }
275
+ return false;
276
+ };
277
+ const evaluateTarget = ({ position, value }) => {
278
+ switch (value.type) {
279
+ case "next": return position + 1;
280
+ case "jump": return value.target;
281
+ case "end": return null;
282
+ }
283
+ };
284
+ const evaluateCondition = ({ answer, condition }) => {
285
+ const value = evaluateValue(condition.value);
286
+ switch (condition.operator) {
287
+ case "equal": return answer === value;
288
+ case "not-equal": return answer !== value;
289
+ case "greater": return typeof answer === "number" && typeof value === "number" && answer > value;
290
+ case "greater-or-equal": return typeof answer === "number" && typeof value === "number" && answer >= value;
291
+ case "less": return typeof answer === "number" && typeof value === "number" && answer < value;
292
+ case "less-or-equal": return typeof answer === "number" && typeof value === "number" && answer <= value;
293
+ case "contains": return Array.isArray(answer) && typeof value === "string" && answer.includes(value);
294
+ case "not-contains": return Array.isArray(answer) && typeof value === "string" && !answer.includes(value);
295
+ }
296
+ };
297
+ const evaluateValue = (node) => {
298
+ return node.value;
299
+ };
300
+
301
+ //#endregion
302
+ //#region src/core/logic/validate.ts
303
+ const VALIDATOR_FACTORY_MAP = {
304
+ rating: ({ scale }, meta) => ratingAnswerSchemaFactory({ scale }, meta),
305
+ "open-ended": ({ max }, meta) => openEndedAnswerSchemaFactory({ maxLength: max }, meta),
306
+ "single-select": ({ editable }, meta) => singleSelectAnswerSchemaFactory({ maxLength: editable?.max }, meta),
307
+ "multi-select": ({ editable, max }, meta) => multiSelectAnswerSchemaFactory({
308
+ maxLength: editable?.max,
309
+ maxSelected: max
310
+ }, meta)
311
+ };
312
+ const getAnswerValidator = (properties, meta) => {
313
+ const type = properties.type;
314
+ switch (type) {
315
+ case "rating": {
316
+ const validator = VALIDATOR_FACTORY_MAP[type];
317
+ return validator(properties, meta);
318
+ }
319
+ case "open-ended": {
320
+ const validator = VALIDATOR_FACTORY_MAP[type];
321
+ return validator(properties, meta);
322
+ }
323
+ case "single-select": {
324
+ const validator = VALIDATOR_FACTORY_MAP[type];
325
+ return validator(properties, meta);
326
+ }
327
+ case "multi-select": {
328
+ const validator = VALIDATOR_FACTORY_MAP[type];
329
+ return validator(properties, meta);
330
+ }
331
+ default: throw new Error("Unsupported question type");
332
+ }
333
+ };
334
+
335
+ //#endregion
336
+ //#region src/core/ConfettiController.tsx
336
337
  const getNextQuestionState = ({ originalQuestions, answers, errors, pointer = -1 }) => {
337
338
  if (!originalQuestions) return {
338
339
  questions: [],
@@ -578,23 +579,29 @@ const FreeText = ({ id, title, description, properties, onChange, classNames, re
578
579
 
579
580
  //#endregion
580
581
  //#region src/components/questions/MultiChoice.tsx
581
- const MultiChoiceCheckbox = ({ children, classNames, ...props }) => {
582
+ const MultiChoiceCheckbox = ({ children, classNames, description, ...props }) => {
582
583
  return /* @__PURE__ */ jsx(Checkbox, {
583
584
  ...props,
584
- children: ({ isIndeterminate }) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
585
- className: clsx("cf-checkbox-indicator", classNames?.indicator),
586
- children: /* @__PURE__ */ jsx("svg", {
587
- viewBox: "0 0 18 18",
588
- "aria-hidden": "true",
589
- className: clsx("cf-checkbox-indicator-svg", classNames?.svg),
590
- children: isIndeterminate ? /* @__PURE__ */ jsx("rect", {
591
- x: 1,
592
- y: 7.5,
593
- width: 16,
594
- height: 3
595
- }) : /* @__PURE__ */ jsx("polyline", { points: "2 9 7 14 16 4" })
596
- }, isIndeterminate ? "indeterminate" : "check")
597
- }), children] })
585
+ children: ({ isIndeterminate }) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
586
+ className: clsx("cf-choice-label", classNames?.label),
587
+ children: [/* @__PURE__ */ jsx("div", {
588
+ className: clsx("cf-checkbox-indicator", classNames?.indicator),
589
+ children: /* @__PURE__ */ jsx("svg", {
590
+ viewBox: "0 0 18 18",
591
+ "aria-hidden": "true",
592
+ className: clsx("cf-checkbox-indicator-svg", classNames?.svg),
593
+ children: isIndeterminate ? /* @__PURE__ */ jsx("rect", {
594
+ x: 1,
595
+ y: 7.5,
596
+ width: 16,
597
+ height: 3
598
+ }) : /* @__PURE__ */ jsx("polyline", { points: "2 9 7 14 16 4" })
599
+ }, isIndeterminate ? "indeterminate" : "check")
600
+ }), children]
601
+ }), description && /* @__PURE__ */ jsx("span", {
602
+ className: clsx("cf-choice-description", classNames?.choiceDescription),
603
+ children: description
604
+ })] })
598
605
  });
599
606
  };
600
607
  const MultiChoice = ({ title, description, properties, classNames, onChange, id, required, error }) => {
@@ -635,15 +642,16 @@ const MultiChoice = ({ title, description, properties, classNames, onChange, id,
635
642
  /* @__PURE__ */ jsxs("div", {
636
643
  className: clsx("cf-response-choices", classNames?.group),
637
644
  children: [properties.options.map((option, index) => /* @__PURE__ */ jsx(MultiChoiceCheckbox, {
638
- className: clsx("cf-checkbox", classNames?.checkbox),
645
+ className: clsx("cf-choice cf-checkbox", classNames?.checkbox),
639
646
  value: option.value,
640
647
  classNames: {
641
648
  indicator: classNames?.indicator,
642
649
  svg: classNames?.svg
643
650
  },
644
- children: option.label
651
+ description: option.description,
652
+ children: option.value
645
653
  }, index)), hasEditable && /* @__PURE__ */ jsxs("div", {
646
- className: clsx("cf-others-choice", classNames?.othersChoice),
654
+ className: clsx("cf-choice cf-others-choice", classNames?.othersChoice),
647
655
  children: [/* @__PURE__ */ jsx(MultiChoiceCheckbox, {
648
656
  inputRef: othersRef,
649
657
  onChange: (isSelected) => {
@@ -659,6 +667,7 @@ const MultiChoice = ({ title, description, properties, classNames, onChange, id,
659
667
  indicator: classNames?.indicator,
660
668
  svg: classNames?.svg
661
669
  },
670
+ description: properties.editable?.description,
662
671
  children: properties.editable?.label
663
672
  }), /* @__PURE__ */ jsx(Input, {
664
673
  value: othersValue,
@@ -942,11 +951,17 @@ const Rating = ({ properties, title, description, classNames, onChange, id, erro
942
951
 
943
952
  //#endregion
944
953
  //#region src/components/questions/SingleChoice.tsx
945
- const SingleChoiceRadio = ({ classNames, className, ...props }) => {
954
+ const SingleChoiceRadio = ({ classNames, className, description, ...props }) => {
946
955
  return /* @__PURE__ */ jsx(Radio, {
947
956
  ...props,
948
957
  className: clsx(className, classNames?.radio),
949
- children: composeRenderProps(props.children, (children) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", { className: clsx("cf-radio-indicator", classNames?.indicator) }), children] }))
958
+ children: composeRenderProps(props.children, (children) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
959
+ className: clsx("cf-choice-label", classNames?.label),
960
+ children: [/* @__PURE__ */ jsx("div", { className: clsx("cf-radio-indicator", classNames?.indicator) }), children]
961
+ }), description && /* @__PURE__ */ jsx("span", {
962
+ className: clsx("cf-choice-description", classNames?.choiceDescription),
963
+ children: description
964
+ })] }))
950
965
  });
951
966
  };
952
967
  const SingleChoice = ({ title, description, properties, classNames, onChange, id, required, error }) => {
@@ -992,12 +1007,13 @@ const SingleChoice = ({ title, description, properties, classNames, onChange, id
992
1007
  children: [properties.options.map((option, index) => /* @__PURE__ */ jsx(SingleChoiceRadio, {
993
1008
  classNames: {
994
1009
  indicator: classNames?.indicator,
995
- radio: clsx("cf-radio", classNames?.radio)
1010
+ radio: clsx("cf-choice cf-radio", classNames?.radio)
996
1011
  },
997
1012
  value: option.value,
998
- children: option.label
1013
+ description: option.description,
1014
+ children: option.value
999
1015
  }, index)), hasEditable && /* @__PURE__ */ jsxs("div", {
1000
- className: clsx("cf-others-choice", classNames?.othersChoice),
1016
+ className: clsx("cf-choice cf-others-choice", classNames?.othersChoice),
1001
1017
  children: [/* @__PURE__ */ jsx(SingleChoiceRadio, {
1002
1018
  inputRef: othersRef,
1003
1019
  value: RADIO_OTHERS_VALUE,
@@ -1005,6 +1021,7 @@ const SingleChoice = ({ title, description, properties, classNames, onChange, id
1005
1021
  indicator: classNames?.indicator,
1006
1022
  radio: clsx("cf-radio", classNames?.radio)
1007
1023
  },
1024
+ description: properties.editable?.description,
1008
1025
  children: properties.editable?.label
1009
1026
  }), /* @__PURE__ */ jsx(Input, {
1010
1027
  tabIndex: state.selectedValue === RADIO_OTHERS_VALUE ? 0 : -1,
@@ -1126,6 +1143,40 @@ const EmbeddedConfetti = (props) => {
1126
1143
  });
1127
1144
  };
1128
1145
 
1146
+ //#endregion
1147
+ //#region src/templates/PopoverConfetti.tsx
1148
+ const PopoverConfetti = ({ closeOnFinishMs, ...props }) => {
1149
+ return /* @__PURE__ */ jsx(ConfettiProvider, {
1150
+ ...props,
1151
+ children: /* @__PURE__ */ jsx(PopoverContainer, {
1152
+ closeOnFinishMs,
1153
+ children: ({ setIsFinished }) => /* @__PURE__ */ jsx(ConfettiController, {
1154
+ shouldAutoSubmit: true,
1155
+ ...props,
1156
+ onFinished: () => {
1157
+ setIsFinished();
1158
+ props.onFinished?.();
1159
+ },
1160
+ children: ({ current, questions, update, isSubmitted }) => {
1161
+ if (isSubmitted) return /* @__PURE__ */ jsx(ThankYouMessage, {});
1162
+ const currentQuestion = questions[current];
1163
+ if (!currentQuestion) return /* @__PURE__ */ jsx(Fragment, {});
1164
+ return /* @__PURE__ */ jsx(Flow, {
1165
+ question: currentQuestion,
1166
+ onSubmit: (answer) => {
1167
+ return update({
1168
+ question: current,
1169
+ answer
1170
+ });
1171
+ },
1172
+ children: (flowProps) => /* @__PURE__ */ jsx(SurveyQuestionFactory, { ...flowProps })
1173
+ });
1174
+ }
1175
+ })
1176
+ })
1177
+ });
1178
+ };
1179
+
1129
1180
  //#endregion
1130
1181
  //#region src/templates/StepperConfetti.tsx
1131
1182
  const StepperConfetti = (props) => {
@@ -1151,5 +1202,59 @@ const StepperConfetti = (props) => {
1151
1202
  };
1152
1203
 
1153
1204
  //#endregion
1154
- export { Confetti, ConfettiContext, ConfettiController, ConfettiProvider, Embed, EmbeddedConfetti, Flow, FreeText, MultiChoice, PopoverContainer, Rating, SingleChoice, StepperConfetti, SurveyQuestionFactory, ThankYouMessage, useConfetti };
1205
+ //#region src/hooks/useVisibleAfterDelay.ts
1206
+ const useVisibleAfterDelay = ({ delay }) => {
1207
+ const [isVisible$1, setIsVisible] = useState(false);
1208
+ const initialDelay = useMemo(() => delay, []);
1209
+ useEffect(() => {
1210
+ const timeoutId = setTimeout(() => {
1211
+ setIsVisible(true);
1212
+ }, initialDelay);
1213
+ return () => clearTimeout(timeoutId);
1214
+ }, []);
1215
+ return { isVisible: isVisible$1 };
1216
+ };
1217
+
1218
+ //#endregion
1219
+ //#region src/hooks/useVisibleAfterPageVisits.ts
1220
+ const useVisibleAfterPageVisits = ({ visits, respondent }) => {
1221
+ const [visitCount, setVisitCount] = useLocalStorage(`cfti:${useMemo(() => window.location.pathname, [])}:visits:${respondent ?? ""}`, 0);
1222
+ useEffect(() => {
1223
+ setVisitCount((prev) => prev + 1);
1224
+ }, [setVisitCount]);
1225
+ return {
1226
+ isVisible: visitCount >= visits,
1227
+ reset: useCallback(() => setVisitCount(0), [setVisitCount])
1228
+ };
1229
+ };
1230
+ const useVisibleAfterSessionPageVisits = ({ visits, respondent }) => {
1231
+ const [visitCount, setVisitCount] = useSessionStorage(`cfti:${useMemo(() => window.location.pathname, [])}:visits:${respondent ?? ""}`, 0);
1232
+ useEffect(() => {
1233
+ setVisitCount((prev) => prev + 1);
1234
+ }, [setVisitCount]);
1235
+ return {
1236
+ isVisible: visitCount >= visits,
1237
+ reset: useCallback(() => setVisitCount(0), [setVisitCount])
1238
+ };
1239
+ };
1240
+
1241
+ //#endregion
1242
+ //#region src/hooks/useVisibleAfterScroll.ts
1243
+ const useVisibleAfterScroll = ({ threshold }) => {
1244
+ const [isVisible$1, setIsVisible] = useState(() => {
1245
+ if (typeof window === "undefined") return false;
1246
+ return window.scrollY >= threshold;
1247
+ });
1248
+ useEffect(() => {
1249
+ const handleScroll = () => {
1250
+ if (window.scrollY >= threshold) setIsVisible(true);
1251
+ };
1252
+ window.addEventListener("scroll", handleScroll, { passive: true });
1253
+ return () => window.removeEventListener("scroll", handleScroll);
1254
+ }, [threshold]);
1255
+ return { isVisible: isVisible$1 };
1256
+ };
1257
+
1258
+ //#endregion
1259
+ export { Confetti, ConfettiContext, ConfettiController, ConfettiProvider, Embed, EmbeddedConfetti, Flow, FreeText, MultiChoice, PopoverConfetti, PopoverContainer, Rating, SingleChoice, StepperConfetti, SurveyQuestionFactory, ThankYouMessage, useConfetti, useVisibleAfterDelay, useVisibleAfterPageVisits, useVisibleAfterScroll, useVisibleAfterSessionPageVisits };
1155
1260
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengovsg/confetti",
3
- "version": "0.0.0",
3
+ "version": "0.0.1",
4
4
  "sideEffects": false,
5
5
  "description": "Widgets for Confetti",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -38,10 +38,10 @@
38
38
  "prettier": "^3.7.4",
39
39
  "tsdown": "0.19.0",
40
40
  "typescript": "^5.9.3",
41
- "@confetti/validators": "0.0.0",
42
41
  "@confetti/tsconfig": "0.0.0",
43
- "@confetti/eslint-config": "0.0.0",
44
- "@confetti/prettier-config": "0.0.0"
42
+ "@confetti/validators": "0.0.0",
43
+ "@confetti/prettier-config": "0.0.0",
44
+ "@confetti/eslint-config": "0.0.0"
45
45
  },
46
46
  "prettier": "@confetti/prettier-config",
47
47
  "scripts": {