@openlearning/widget-framework 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/README.md +230 -0
  2. package/dist/components/Button.d.ts +41 -0
  3. package/dist/components/Button.d.ts.map +1 -0
  4. package/dist/components/Button.js +47 -0
  5. package/dist/components/Button.js.map +1 -0
  6. package/dist/components/Checkbox.d.ts +19 -0
  7. package/dist/components/Checkbox.d.ts.map +1 -0
  8. package/dist/components/Checkbox.js +16 -0
  9. package/dist/components/Checkbox.js.map +1 -0
  10. package/dist/components/CheckboxGroup.d.ts +34 -0
  11. package/dist/components/CheckboxGroup.d.ts.map +1 -0
  12. package/dist/components/CheckboxGroup.js +18 -0
  13. package/dist/components/CheckboxGroup.js.map +1 -0
  14. package/dist/components/Menu.d.ts +45 -0
  15. package/dist/components/Menu.d.ts.map +1 -0
  16. package/dist/components/Menu.js +56 -0
  17. package/dist/components/Menu.js.map +1 -0
  18. package/dist/components/RadioGroup.d.ts +36 -0
  19. package/dist/components/RadioGroup.d.ts.map +1 -0
  20. package/dist/components/RadioGroup.js +18 -0
  21. package/dist/components/RadioGroup.js.map +1 -0
  22. package/dist/components/Spinner.d.ts +15 -0
  23. package/dist/components/Spinner.d.ts.map +1 -0
  24. package/dist/components/Spinner.js +10 -0
  25. package/dist/components/Spinner.js.map +1 -0
  26. package/dist/components/StatusTag.d.ts +16 -0
  27. package/dist/components/StatusTag.d.ts.map +1 -0
  28. package/dist/components/StatusTag.js +9 -0
  29. package/dist/components/StatusTag.js.map +1 -0
  30. package/dist/components/Switch.d.ts +22 -0
  31. package/dist/components/Switch.d.ts.map +1 -0
  32. package/dist/components/Switch.js +14 -0
  33. package/dist/components/Switch.js.map +1 -0
  34. package/dist/components/Tabs.d.ts +23 -0
  35. package/dist/components/Tabs.d.ts.map +1 -0
  36. package/dist/components/Tabs.js +27 -0
  37. package/dist/components/Tabs.js.map +1 -0
  38. package/dist/components/TextField.d.ts +19 -0
  39. package/dist/components/TextField.d.ts.map +1 -0
  40. package/dist/components/TextField.js +17 -0
  41. package/dist/components/TextField.js.map +1 -0
  42. package/dist/components/Textarea.d.ts +19 -0
  43. package/dist/components/Textarea.d.ts.map +1 -0
  44. package/dist/components/Textarea.js +17 -0
  45. package/dist/components/Textarea.js.map +1 -0
  46. package/dist/components/icons/IconCaretDown.d.ts +7 -0
  47. package/dist/components/icons/IconCaretDown.d.ts.map +1 -0
  48. package/dist/components/icons/IconCaretDown.js +4 -0
  49. package/dist/components/icons/IconCaretDown.js.map +1 -0
  50. package/dist/components/icons/IconCaretLeft.d.ts +7 -0
  51. package/dist/components/icons/IconCaretLeft.d.ts.map +1 -0
  52. package/dist/components/icons/IconCaretLeft.js +4 -0
  53. package/dist/components/icons/IconCaretLeft.js.map +1 -0
  54. package/dist/components/icons/IconCaretRight.d.ts +7 -0
  55. package/dist/components/icons/IconCaretRight.d.ts.map +1 -0
  56. package/dist/components/icons/IconCaretRight.js +4 -0
  57. package/dist/components/icons/IconCaretRight.js.map +1 -0
  58. package/dist/components/icons/IconCaretUp.d.ts +7 -0
  59. package/dist/components/icons/IconCaretUp.d.ts.map +1 -0
  60. package/dist/components/icons/IconCaretUp.js +4 -0
  61. package/dist/components/icons/IconCaretUp.js.map +1 -0
  62. package/dist/components/icons/IconChevronLeft.d.ts +7 -0
  63. package/dist/components/icons/IconChevronLeft.d.ts.map +1 -0
  64. package/dist/components/icons/IconChevronLeft.js +4 -0
  65. package/dist/components/icons/IconChevronLeft.js.map +1 -0
  66. package/dist/components/icons/IconChevronRight.d.ts +7 -0
  67. package/dist/components/icons/IconChevronRight.d.ts.map +1 -0
  68. package/dist/components/icons/IconChevronRight.js +4 -0
  69. package/dist/components/icons/IconChevronRight.js.map +1 -0
  70. package/dist/components/icons/IconFastForward.d.ts +7 -0
  71. package/dist/components/icons/IconFastForward.d.ts.map +1 -0
  72. package/dist/components/icons/IconFastForward.js +4 -0
  73. package/dist/components/icons/IconFastForward.js.map +1 -0
  74. package/dist/components/icons/IconNext.d.ts +7 -0
  75. package/dist/components/icons/IconNext.d.ts.map +1 -0
  76. package/dist/components/icons/IconNext.js +4 -0
  77. package/dist/components/icons/IconNext.js.map +1 -0
  78. package/dist/components/icons/IconPause.d.ts +7 -0
  79. package/dist/components/icons/IconPause.d.ts.map +1 -0
  80. package/dist/components/icons/IconPause.js +4 -0
  81. package/dist/components/icons/IconPause.js.map +1 -0
  82. package/dist/components/icons/IconPlay.d.ts +7 -0
  83. package/dist/components/icons/IconPlay.d.ts.map +1 -0
  84. package/dist/components/icons/IconPlay.js +4 -0
  85. package/dist/components/icons/IconPlay.js.map +1 -0
  86. package/dist/components/icons/IconPlus.d.ts +7 -0
  87. package/dist/components/icons/IconPlus.d.ts.map +1 -0
  88. package/dist/components/icons/IconPlus.js +4 -0
  89. package/dist/components/icons/IconPlus.js.map +1 -0
  90. package/dist/components/icons/IconPrevious.d.ts +7 -0
  91. package/dist/components/icons/IconPrevious.d.ts.map +1 -0
  92. package/dist/components/icons/IconPrevious.js +4 -0
  93. package/dist/components/icons/IconPrevious.js.map +1 -0
  94. package/dist/components/icons/IconRedo.d.ts +7 -0
  95. package/dist/components/icons/IconRedo.d.ts.map +1 -0
  96. package/dist/components/icons/IconRedo.js +4 -0
  97. package/dist/components/icons/IconRedo.js.map +1 -0
  98. package/dist/components/icons/IconReload.d.ts +7 -0
  99. package/dist/components/icons/IconReload.d.ts.map +1 -0
  100. package/dist/components/icons/IconReload.js +4 -0
  101. package/dist/components/icons/IconReload.js.map +1 -0
  102. package/dist/components/icons/IconReplay.d.ts +3 -0
  103. package/dist/components/icons/IconReplay.d.ts.map +1 -0
  104. package/dist/components/icons/IconReplay.js +4 -0
  105. package/dist/components/icons/IconReplay.js.map +1 -0
  106. package/dist/components/icons/IconRewind.d.ts +7 -0
  107. package/dist/components/icons/IconRewind.d.ts.map +1 -0
  108. package/dist/components/icons/IconRewind.js +4 -0
  109. package/dist/components/icons/IconRewind.js.map +1 -0
  110. package/dist/components/icons/IconSkipBackward.d.ts +7 -0
  111. package/dist/components/icons/IconSkipBackward.d.ts.map +1 -0
  112. package/dist/components/icons/IconSkipBackward.js +4 -0
  113. package/dist/components/icons/IconSkipBackward.js.map +1 -0
  114. package/dist/components/icons/IconSkipForward.d.ts +7 -0
  115. package/dist/components/icons/IconSkipForward.d.ts.map +1 -0
  116. package/dist/components/icons/IconSkipForward.js +4 -0
  117. package/dist/components/icons/IconSkipForward.js.map +1 -0
  118. package/dist/components/icons/IconStop.d.ts +7 -0
  119. package/dist/components/icons/IconStop.d.ts.map +1 -0
  120. package/dist/components/icons/IconStop.js +4 -0
  121. package/dist/components/icons/IconStop.js.map +1 -0
  122. package/dist/components/icons/IconUndo.d.ts +7 -0
  123. package/dist/components/icons/IconUndo.d.ts.map +1 -0
  124. package/dist/components/icons/IconUndo.js +4 -0
  125. package/dist/components/icons/IconUndo.js.map +1 -0
  126. package/dist/components/icons/IconX.d.ts +7 -0
  127. package/dist/components/icons/IconX.d.ts.map +1 -0
  128. package/dist/components/icons/IconX.js +4 -0
  129. package/dist/components/icons/IconX.js.map +1 -0
  130. package/dist/components/icons/index.d.ts +21 -0
  131. package/dist/components/icons/index.d.ts.map +1 -0
  132. package/dist/components/icons/index.js +21 -0
  133. package/dist/components/icons/index.js.map +1 -0
  134. package/dist/index.d.ts +11 -0
  135. package/dist/index.d.ts.map +1 -1
  136. package/dist/index.js +13 -0
  137. package/dist/index.js.map +1 -1
  138. package/dist/styles/button.css +381 -0
  139. package/dist/styles/checkbox.css +105 -0
  140. package/dist/styles/checkboxgroup.css +42 -0
  141. package/dist/styles/radiogroup.css +135 -0
  142. package/dist/styles/spinner.css +22 -0
  143. package/dist/styles/statustag.css +35 -0
  144. package/dist/styles/switch.css +74 -0
  145. package/dist/styles/tabs.css +49 -0
  146. package/dist/styles/textfield.css +72 -0
  147. package/package.json +12 -7
package/README.md ADDED
@@ -0,0 +1,230 @@
1
+ # Widget Framework
2
+
3
+ A comprehensive framework for building OpenLearning widgets with reusable UI components, parent-window messaging, and configuration management.
4
+
5
+ ## Features
6
+
7
+ - **Reusable UI Components**: Pre-built, accessible components following the OpenLearning design system
8
+ - **Parent Messaging**: Secure two-way communication between widgets and parent applications
9
+ - **Configuration Management**: Type-safe widget configuration and setup
10
+ - **TypeScript Support**: Full TypeScript support with comprehensive type definitions
11
+ - **Consistent Styling**: CSS-based theming with customizable color variables
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @openlearning/widget-framework
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ### 1. Create Your Widget Component
22
+
23
+ ```typescript
24
+ import React from "react";
25
+ import { Button } from "@openlearning/widget-framework";
26
+ import "@openlearning/widget-framework/styles/button.css";
27
+
28
+ export function MyWidget() {
29
+ return (
30
+ <div>
31
+ <h1>My First Widget</h1>
32
+ <Button theme="cta">Get Started</Button>
33
+ </div>
34
+ );
35
+ }
36
+ ```
37
+
38
+ ### 2. Set Up the Learner View
39
+
40
+ ```typescript
41
+ import { createLearnerEntry } from "@openlearning/widget-framework";
42
+ import MyWidget from "./MyWidget";
43
+
44
+ createLearnerEntry(MyWidget);
45
+ ```
46
+
47
+ ### 3. Set Up the Setup View
48
+
49
+ ```typescript
50
+ import { createSetupEntry } from "@openlearning/widget-framework";
51
+ import MyWidgetSetup from "./MyWidgetSetup";
52
+
53
+ createSetupEntry(MyWidgetSetup);
54
+ ```
55
+
56
+ ## Core Features
57
+
58
+ ### UI Components
59
+
60
+ See [COMPONENTS.md](./COMPONENTS.md) for full component documentation.
61
+
62
+ ### Parent Messaging
63
+
64
+ Communicate securely with the parent application:
65
+
66
+ ```typescript
67
+ import { useParentMessaging } from "@openlearning/widget-framework";
68
+
69
+ function MyComponent() {
70
+ const { send, subscribe } = useParentMessaging();
71
+
72
+ const handleAction = () => {
73
+ send({
74
+ type: "action",
75
+ payload: { /* your data */ }
76
+ });
77
+ };
78
+
79
+ subscribe((message) => {
80
+ console.log("Parent message:", message);
81
+ });
82
+
83
+ return <button onClick={handleAction}>Send Message</button>;
84
+ }
85
+ ```
86
+
87
+ ### Configuration Management
88
+
89
+ Access and manage widget configuration:
90
+
91
+ ```typescript
92
+ import { useWidgetConfig } from "@openlearning/widget-framework";
93
+
94
+ function MyComponent() {
95
+ const config = useWidgetConfig();
96
+
97
+ return <div>Theme: {config.theme}</div>;
98
+ }
99
+ ```
100
+
101
+ ### Development Tools
102
+
103
+ Use `DevApp` for development and testing:
104
+
105
+ ```typescript
106
+ import { DevApp } from "@openlearning/widget-framework";
107
+
108
+ export default function App() {
109
+ return (
110
+ <DevApp
111
+ LearnerView={MyLearnerWidget}
112
+ SetupView={MySetupWidget}
113
+ />
114
+ );
115
+ }
116
+ ```
117
+
118
+ ## Project Setup
119
+
120
+ Define your widget project configuration:
121
+
122
+ ```typescript
123
+ import { defineWidgetProject } from "@openlearning/widget-framework";
124
+
125
+ export const widgetConfig = defineWidgetProject({
126
+ id: "my-widget",
127
+ name: "My Widget",
128
+ version: "1.0.0",
129
+ /* ... more config ... */
130
+ });
131
+ ```
132
+
133
+ ## Integration Guide
134
+
135
+ See [INTEGRATION_GUIDE.md](./INTEGRATION_GUIDE.md) for practical examples and common patterns.
136
+
137
+ ## API Reference
138
+
139
+ ### `createLearnerEntry(Component)`
140
+ Renders a component as the learner view of your widget.
141
+
142
+ ### `createSetupEntry(Component)`
143
+ Renders a component as the setup/configuration view of your widget.
144
+
145
+ ### `useParentMessaging()`
146
+ Hook for parent-window communication. Returns `{ send, subscribe }`.
147
+
148
+ ### `useWidgetConfig()`
149
+ Hook to access widget configuration.
150
+
151
+ ### `DevApp(props)`
152
+ Development wrapper component for testing widget views.
153
+
154
+ ### `defineWidgetProject(config)`
155
+ Defines widget project configuration.
156
+
157
+ ### UI Components
158
+
159
+ #### Button
160
+
161
+ ```typescript
162
+ import { Button } from "@openlearning/widget-framework";
163
+ import "@openlearning/widget-framework/styles/button.css";
164
+
165
+ <Button
166
+ variant="filled"
167
+ theme="primary"
168
+ size="medium"
169
+ icon={<MyIcon />}
170
+ iconPosition="left"
171
+ isLoading={false}
172
+ fullWidth={false}
173
+ onClick={handleClick}
174
+ >
175
+ Click Me
176
+ </Button>
177
+ ```
178
+
179
+ ## CSS Customization
180
+
181
+ Override styling by setting CSS variables:
182
+
183
+ ```css
184
+ :root {
185
+ --btn-primary-bg: #4a90e2;
186
+ --btn-primary-bg-hover: #357abd;
187
+ --btn-cta-bg: #10b981;
188
+ /* ... more variables ... */
189
+ }
190
+ ```
191
+
192
+ See [button.css](./src/styles/button.css) for all available variables.
193
+
194
+ ## TypeScript Support
195
+
196
+ Full TypeScript support with type definitions:
197
+
198
+ ```typescript
199
+ import {
200
+ Button,
201
+ type ButtonProps,
202
+ type LearnerViewProps,
203
+ type WidgetConfigBase
204
+ } from "@openlearning/widget-framework";
205
+ ```
206
+
207
+ ## Browser Support
208
+
209
+ - Chrome/Edge (latest 2 versions)
210
+ - Firefox (latest 2 versions)
211
+ - Safari (latest 2 versions)
212
+ - iOS Safari 12+
213
+ - Android 5+
214
+
215
+ ## Contributing
216
+
217
+ Contributions are welcome! Please follow these guidelines:
218
+
219
+ 1. Create a feature branch
220
+ 2. Make your changes
221
+ 3. Write tests for new functionality
222
+ 4. Submit a pull request
223
+
224
+ ## License
225
+
226
+ MIT
227
+
228
+ ## Support
229
+
230
+ For issues, questions, or feature requests, please contact the OpenLearning team.
@@ -0,0 +1,41 @@
1
+ import React, { ReactNode } from "react";
2
+ import "../styles/button.css";
3
+ export type ButtonVariant = "round-filled" | "round-tonal" | "round-quiet" | "round-inline" | "primary" | "secondary";
4
+ export type ButtonSize = "small" | "medium" | "large";
5
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
6
+ /** Visual variant of the button */
7
+ variant?: ButtonVariant;
8
+ /** Size of the button */
9
+ size?: ButtonSize;
10
+ /** Icon to display */
11
+ icon?: ReactNode;
12
+ /** Icon position */
13
+ iconPosition?: "left" | "right";
14
+ /** Whether button is loading */
15
+ isLoading?: boolean;
16
+ /** Custom loading indicator component */
17
+ loadingIndicator?: ReactNode;
18
+ /** Whether button takes full width */
19
+ fullWidth?: boolean;
20
+ /** Custom className to merge with button classes */
21
+ className?: string;
22
+ /** Button content/children */
23
+ children?: ReactNode;
24
+ }
25
+ /**
26
+ * Reusable Button component following OpenLearning design system
27
+ *
28
+ * @example
29
+ * // Basic usage
30
+ * <Button>Click me</Button>
31
+ *
32
+ * @example
33
+ * // With variant
34
+ * <Button variant="filled">Submit</Button>
35
+ *
36
+ * @example
37
+ * // With icon
38
+ * <Button icon={<IconComponent />} iconPosition="left">Action</Button>
39
+ */
40
+ export declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
41
+ //# sourceMappingURL=Button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../src/components/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,sBAAsB,CAAC;AAG9B,MAAM,MAAM,aAAa,GAAG,cAAc,GAAG,aAAa,GAAG,aAAa,GAAG,cAAc,GAAG,SAAS,GAAG,WAAW,CAAC;AACtH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEtD,MAAM,WAAW,WACf,SAAQ,KAAK,CAAC,oBAAoB,CAAC,iBAAiB,CAAC;IACrD,mCAAmC;IACnC,OAAO,CAAC,EAAE,aAAa,CAAC;IAExB,yBAAyB;IACzB,IAAI,CAAC,EAAE,UAAU,CAAC;IAElB,sBAAsB;IACtB,IAAI,CAAC,EAAE,SAAS,CAAC;IAEjB,oBAAoB;IACpB,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAEhC,gCAAgC;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAE7B,sCAAsC;IACtC,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,MAAM,uFAqElB,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import "../styles/button.css";
4
+ import { Spinner } from "./Spinner";
5
+ /**
6
+ * Reusable Button component following OpenLearning design system
7
+ *
8
+ * @example
9
+ * // Basic usage
10
+ * <Button>Click me</Button>
11
+ *
12
+ * @example
13
+ * // With variant
14
+ * <Button variant="filled">Submit</Button>
15
+ *
16
+ * @example
17
+ * // With icon
18
+ * <Button icon={<IconComponent />} iconPosition="left">Action</Button>
19
+ */
20
+ export const Button = React.forwardRef(({ variant = "primary", size = "medium", icon, iconPosition = "left", isLoading = false, loadingIndicator, fullWidth = false, className = "", children, disabled, ...rest }, ref) => {
21
+ const isDisabled = disabled;
22
+ // Build class names
23
+ const classes = [
24
+ "btn",
25
+ `btn--${variant}`,
26
+ size !== "medium" && `btn--${size}`,
27
+ isLoading && "btn--loading",
28
+ fullWidth && "btn--full-width",
29
+ !children && icon && "btn--icon-only",
30
+ className,
31
+ ]
32
+ .filter(Boolean)
33
+ .join(" ");
34
+ // Build content
35
+ let content = children;
36
+ if (isLoading) {
37
+ content = (_jsxs(_Fragment, { children: [loadingIndicator || _jsx(Spinner, {}), children && _jsx("span", { children: children })] }));
38
+ }
39
+ else if (icon) {
40
+ const iconElement = _jsx("span", { className: "btn__icon", children: icon });
41
+ content =
42
+ iconPosition === "right" ? (_jsxs(_Fragment, { children: [children, iconElement] })) : (_jsxs(_Fragment, { children: [iconElement, children] }));
43
+ }
44
+ return (_jsx("button", { ref: ref, className: classes, disabled: isDisabled, ...rest, children: content }));
45
+ });
46
+ Button.displayName = "Button";
47
+ //# sourceMappingURL=Button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.js","sourceRoot":"","sources":["../../src/components/Button.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AACzC,OAAO,sBAAsB,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmCpC;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CACpC,CACE,EACE,OAAO,GAAG,SAAS,EACnB,IAAI,GAAG,QAAQ,EACf,IAAI,EACJ,YAAY,GAAG,MAAM,EACrB,SAAS,GAAG,KAAK,EACjB,gBAAgB,EAChB,SAAS,GAAG,KAAK,EACjB,SAAS,GAAG,EAAE,EACd,QAAQ,EACR,QAAQ,EACR,GAAG,IAAI,EACR,EACD,GAAG,EACH,EAAE;IACF,MAAM,UAAU,GAAG,QAAQ,CAAC;IAE5B,oBAAoB;IACpB,MAAM,OAAO,GAAG;QACd,KAAK;QACL,QAAQ,OAAO,EAAE;QACjB,IAAI,KAAK,QAAQ,IAAI,QAAQ,IAAI,EAAE;QACnC,SAAS,IAAI,cAAc;QAC3B,SAAS,IAAI,iBAAiB;QAC9B,CAAC,QAAQ,IAAI,IAAI,IAAI,gBAAgB;QACrC,SAAS;KACV;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;IAEb,gBAAgB;IAChB,IAAI,OAAO,GAAc,QAAQ,CAAC;IAElC,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,GAAG,CACR,8BACG,gBAAgB,IAAI,KAAC,OAAO,KAAG,EAC/B,QAAQ,IAAI,yBAAO,QAAQ,GAAQ,IACnC,CACJ,CAAC;IACJ,CAAC;SAAM,IAAI,IAAI,EAAE,CAAC;QAChB,MAAM,WAAW,GAAG,eAAM,SAAS,EAAC,WAAW,YAAE,IAAI,GAAQ,CAAC;QAC9D,OAAO;YACL,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,CACzB,8BACG,QAAQ,EACR,WAAW,IACX,CACJ,CAAC,CAAC,CAAC,CACF,8BACG,WAAW,EACX,QAAQ,IACR,CACJ,CAAC;IACN,CAAC;IAED,OAAO,CACL,iBACE,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,OAAO,EAClB,QAAQ,EAAE,UAAU,KAChB,IAAI,YAEP,OAAO,GACD,CACV,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,WAAW,GAAG,QAAQ,CAAC"}
@@ -0,0 +1,19 @@
1
+ import React from "react";
2
+ import "../styles/checkbox.css";
3
+ export interface CheckboxProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> {
4
+ /** Checkbox label */
5
+ label?: React.ReactNode;
6
+ /** Error message to display */
7
+ error?: string | null;
8
+ /** Helper text that appears below the checkbox */
9
+ description?: React.ReactNode;
10
+ /** Whether the checkbox is required */
11
+ required?: boolean;
12
+ /** Called when checked state changes */
13
+ onChange?: (checked: boolean) => void;
14
+ }
15
+ /**
16
+ * Checkbox component matching OpenLearning UI design
17
+ */
18
+ export declare const Checkbox: React.ForwardRefExoticComponent<CheckboxProps & React.RefAttributes<HTMLInputElement>>;
19
+ //# sourceMappingURL=Checkbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Checkbox.d.ts","sourceRoot":"","sources":["../../src/components/Checkbox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,wBAAwB,CAAC;AAEhC,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,UAAU,CAAC;IAClG,qBAAqB;IACrB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,kDAAkD;IAClD,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACvC;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ,wFAkDpB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import "../styles/checkbox.css";
4
+ /**
5
+ * Checkbox component matching OpenLearning UI design
6
+ */
7
+ export const Checkbox = React.forwardRef(({ label, error, description, required, className = "", onChange, disabled, ...rest }, ref) => {
8
+ const handleChange = (event) => {
9
+ if (onChange) {
10
+ onChange(event.target.checked);
11
+ }
12
+ };
13
+ return (_jsxs("div", { className: `checkbox-container ${className}`, children: [_jsxs("label", { className: `checkbox-label ${disabled ? 'checkbox-label--disabled' : ''}`, children: [_jsx("input", { ref: ref, type: "checkbox", className: "checkbox-input", disabled: disabled, onChange: handleChange, ...rest }), _jsx("span", { className: "checkbox-box", children: _jsx("svg", { viewBox: "0 0 20 20", fill: "none", stroke: disabled ? "rgba(0, 0, 0, 0.25)" : "rgba(0, 0, 0, 0.9)", strokeWidth: "3", children: _jsx("polyline", { points: "16 5 8 14 4 10" }) }) }), label && (_jsxs("span", { className: "checkbox-text", children: [label, required && _jsx("span", { className: "checkbox-required", children: " *" })] }))] }), description && !error && (_jsx("div", { className: "checkbox-description", children: description })), error && _jsx("div", { className: "checkbox-error", children: error })] }));
14
+ });
15
+ Checkbox.displayName = "Checkbox";
16
+ //# sourceMappingURL=Checkbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Checkbox.js","sourceRoot":"","sources":["../../src/components/Checkbox.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,wBAAwB,CAAC;AAehC;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CACtC,CACE,EACE,KAAK,EACL,KAAK,EACL,WAAW,EACX,QAAQ,EACR,SAAS,GAAG,EAAE,EACd,QAAQ,EACR,QAAQ,EACR,GAAG,IAAI,EACR,EACD,GAAG,EACH,EAAE;IACF,MAAM,YAAY,GAAG,CAAC,KAA0C,EAAE,EAAE;QAClE,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAE,sBAAsB,SAAS,EAAE,aAC/C,iBAAO,SAAS,EAAE,kBAAkB,QAAQ,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,EAAE,EAAE,aAC9E,gBACE,GAAG,EAAE,GAAG,EACR,IAAI,EAAC,UAAU,EACf,SAAS,EAAC,gBAAgB,EAC1B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,YAAY,KAClB,IAAI,GACR,EACF,eAAM,SAAS,EAAC,cAAc,YAC5B,cAAK,OAAO,EAAC,WAAW,EAAC,IAAI,EAAC,MAAM,EAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,oBAAoB,EAAE,WAAW,EAAC,GAAG,YACnH,mBAAU,MAAM,EAAC,gBAAgB,GAAG,GAChC,GACD,EACN,KAAK,IAAI,CACR,gBAAM,SAAS,EAAC,eAAe,aAC5B,KAAK,EACL,QAAQ,IAAI,eAAM,SAAS,EAAC,mBAAmB,mBAAU,IACrD,CACR,IACK,EACP,WAAW,IAAI,CAAC,KAAK,IAAI,CACxB,cAAK,SAAS,EAAC,sBAAsB,YAAE,WAAW,GAAO,CAC1D,EACA,KAAK,IAAI,cAAK,SAAS,EAAC,gBAAgB,YAAE,KAAK,GAAO,IACnD,CACP,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,QAAQ,CAAC,WAAW,GAAG,UAAU,CAAC"}
@@ -0,0 +1,34 @@
1
+ import React from "react";
2
+ import "../styles/checkboxgroup.css";
3
+ export interface CheckboxGroupOption {
4
+ value: string;
5
+ label: React.ReactNode;
6
+ disabled?: boolean;
7
+ }
8
+ export interface CheckboxGroupProps {
9
+ /** List of checkbox options */
10
+ options: CheckboxGroupOption[];
11
+ /** Currently selected values */
12
+ values?: string[];
13
+ /** Called when selection changes */
14
+ onChange?: (values: string[]) => void;
15
+ /** Group label */
16
+ label?: React.ReactNode;
17
+ /** Error message */
18
+ error?: string | null;
19
+ /** Helper text */
20
+ description?: React.ReactNode;
21
+ /** Whether the group is required */
22
+ required?: boolean;
23
+ /** Whether all options are disabled */
24
+ disabled?: boolean;
25
+ /** Layout direction for options */
26
+ layout?: 'horizontal' | 'vertical';
27
+ /** Additional class name */
28
+ className?: string;
29
+ }
30
+ /**
31
+ * CheckboxGroup component for multiple selections
32
+ */
33
+ export declare const CheckboxGroup: React.FC<CheckboxGroupProps>;
34
+ //# sourceMappingURL=CheckboxGroup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckboxGroup.d.ts","sourceRoot":"","sources":["../../src/components/CheckboxGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,6BAA6B,CAAC;AAErC,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,+BAA+B;IAC/B,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,gCAAgC;IAChC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtC,kBAAkB;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,kBAAkB;IAClB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mCAAmC;IACnC,MAAM,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACnC,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA+CtD,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Checkbox } from "./Checkbox";
3
+ import "../styles/checkboxgroup.css";
4
+ /**
5
+ * CheckboxGroup component for multiple selections
6
+ */
7
+ export const CheckboxGroup = ({ options, values = [], onChange, label, error, description, required, disabled = false, layout = 'horizontal', className = "", }) => {
8
+ const handleChange = (optionValue, checked) => {
9
+ if (!disabled && onChange) {
10
+ const newValues = checked
11
+ ? [...values, optionValue]
12
+ : values.filter((v) => v !== optionValue);
13
+ onChange(newValues);
14
+ }
15
+ };
16
+ return (_jsxs("div", { className: `checkboxgroup-container ${className}`, children: [label && (_jsxs("div", { className: "checkboxgroup-label", children: [label, required && _jsx("span", { className: "checkboxgroup-required", children: " *" })] })), _jsx("div", { className: `checkboxgroup-options checkboxgroup-options--${layout}`, children: options.map((option, index) => (_jsx(Checkbox, { label: option.label, checked: values.includes(option.value), disabled: disabled || option.disabled, onChange: (checked) => handleChange(option.value, checked), className: index > 0 ? 'checkbox--spaced' : '' }, option.value))) }), description && !error && (_jsx("div", { className: "checkboxgroup-description", children: description })), error && _jsx("div", { className: "checkboxgroup-error", children: error })] }));
17
+ };
18
+ //# sourceMappingURL=CheckboxGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CheckboxGroup.js","sourceRoot":"","sources":["../../src/components/CheckboxGroup.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,6BAA6B,CAAC;AA+BrC;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAiC,CAAC,EAC1D,OAAO,EACP,MAAM,GAAG,EAAE,EACX,QAAQ,EACR,KAAK,EACL,KAAK,EACL,WAAW,EACX,QAAQ,EACR,QAAQ,GAAG,KAAK,EAChB,MAAM,GAAG,YAAY,EACrB,SAAS,GAAG,EAAE,GACf,EAAE,EAAE;IACH,MAAM,YAAY,GAAG,CAAC,WAAmB,EAAE,OAAgB,EAAE,EAAE;QAC7D,IAAI,CAAC,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,OAAO;gBACvB,CAAC,CAAC,CAAC,GAAG,MAAM,EAAE,WAAW,CAAC;gBAC1B,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC;YAC5C,QAAQ,CAAC,SAAS,CAAC,CAAC;QACtB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAE,2BAA2B,SAAS,EAAE,aACnD,KAAK,IAAI,CACR,eAAK,SAAS,EAAC,qBAAqB,aACjC,KAAK,EACL,QAAQ,IAAI,eAAM,SAAS,EAAC,wBAAwB,mBAAU,IAC3D,CACP,EACD,cAAK,SAAS,EAAE,gDAAgD,MAAM,EAAE,YACrE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAC9B,KAAC,QAAQ,IAEP,KAAK,EAAE,MAAM,CAAC,KAAK,EACnB,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EACtC,QAAQ,EAAE,QAAQ,IAAI,MAAM,CAAC,QAAQ,EACrC,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,EAC1D,SAAS,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,IALzC,MAAM,CAAC,KAAK,CAMjB,CACH,CAAC,GACE,EACL,WAAW,IAAI,CAAC,KAAK,IAAI,CACxB,cAAK,SAAS,EAAC,2BAA2B,YAAE,WAAW,GAAO,CAC/D,EACA,KAAK,IAAI,cAAK,SAAS,EAAC,qBAAqB,YAAE,KAAK,GAAO,IACxD,CACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,45 @@
1
+ import React, { ReactNode } from "react";
2
+ export interface MenuItem {
3
+ id: string;
4
+ label: string;
5
+ icon?: ReactNode;
6
+ disabled?: boolean;
7
+ checked?: boolean;
8
+ divider?: boolean;
9
+ }
10
+ export interface MenuProps extends React.HTMLAttributes<HTMLDivElement> {
11
+ /** Menu trigger button content/label */
12
+ trigger: ReactNode;
13
+ /** Menu items to display */
14
+ items: MenuItem[];
15
+ /** Called when a menu item is clicked */
16
+ onItemClick?: (itemId: string) => void;
17
+ /** Trigger button icon */
18
+ triggerIcon?: ReactNode;
19
+ /** Custom trigger button class name */
20
+ triggerClassName?: string;
21
+ /** Disable the menu trigger */
22
+ triggerDisabled?: boolean;
23
+ }
24
+ /**
25
+ * Menu component for displaying dropdown menus
26
+ *
27
+ * @example
28
+ * // Basic usage
29
+ * const items = [
30
+ * { id: 'edit', label: 'Edit' },
31
+ * { id: 'delete', label: 'Delete' },
32
+ * ];
33
+ * <Menu trigger="Actions" items={items} onItemClick={(id) => handleAction(id)} />
34
+ *
35
+ * @example
36
+ * // With icons and divider
37
+ * const items = [
38
+ * { id: 'edit', label: 'Edit', icon: <EditIcon /> },
39
+ * { divider: true },
40
+ * { id: 'delete', label: 'Delete', icon: <TrashIcon /> },
41
+ * ];
42
+ * <Menu trigger={<MoreIcon />} items={items} />
43
+ */
44
+ export declare const Menu: React.ForwardRefExoticComponent<MenuProps & React.RefAttributes<HTMLDivElement>>;
45
+ //# sourceMappingURL=Menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Menu.d.ts","sourceRoot":"","sources":["../../src/components/Menu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAA+B,MAAM,OAAO,CAAC;AAEtE,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,SAAU,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACrE,wCAAwC;IACxC,OAAO,EAAE,SAAS,CAAC;IAEnB,4BAA4B;IAC5B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAElB,yCAAyC;IACzC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAEvC,0BAA0B;IAC1B,WAAW,CAAC,EAAE,SAAS,CAAC;IAExB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,+BAA+B;IAC/B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,IAAI,kFA2HhB,CAAC"}
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useState, useRef, useEffect } from "react";
3
+ /**
4
+ * Menu component for displaying dropdown menus
5
+ *
6
+ * @example
7
+ * // Basic usage
8
+ * const items = [
9
+ * { id: 'edit', label: 'Edit' },
10
+ * { id: 'delete', label: 'Delete' },
11
+ * ];
12
+ * <Menu trigger="Actions" items={items} onItemClick={(id) => handleAction(id)} />
13
+ *
14
+ * @example
15
+ * // With icons and divider
16
+ * const items = [
17
+ * { id: 'edit', label: 'Edit', icon: <EditIcon /> },
18
+ * { divider: true },
19
+ * { id: 'delete', label: 'Delete', icon: <TrashIcon /> },
20
+ * ];
21
+ * <Menu trigger={<MoreIcon />} items={items} />
22
+ */
23
+ export const Menu = React.forwardRef(({ trigger, items, onItemClick, triggerIcon, triggerClassName = "", triggerDisabled = false, className = "", ...rest }, ref) => {
24
+ const [isOpen, setIsOpen] = useState(false);
25
+ const menuRef = useRef(null);
26
+ const triggerRef = useRef(null);
27
+ // Close menu when clicking outside
28
+ useEffect(() => {
29
+ const handleClickOutside = (event) => {
30
+ if (menuRef.current &&
31
+ !menuRef.current.contains(event.target) &&
32
+ !triggerRef.current?.contains(event.target)) {
33
+ setIsOpen(false);
34
+ }
35
+ };
36
+ if (isOpen) {
37
+ document.addEventListener("mousedown", handleClickOutside);
38
+ return () => {
39
+ document.removeEventListener("mousedown", handleClickOutside);
40
+ };
41
+ }
42
+ }, [isOpen]);
43
+ const handleItemClick = (itemId) => {
44
+ onItemClick?.(itemId);
45
+ setIsOpen(false);
46
+ };
47
+ const hasCheckedItems = items.some((item) => item.checked);
48
+ return (_jsxs("div", { ref: ref, className: `menu ${className}`.trim(), ...rest, children: [_jsxs("button", { ref: triggerRef, className: `menu__trigger ${isOpen ? "menu__trigger--open" : ""} ${triggerClassName}`.trim(), onClick: () => setIsOpen(!isOpen), disabled: triggerDisabled, "aria-haspopup": "true", "aria-expanded": isOpen, children: [triggerIcon && _jsx("span", { className: "menu__trigger-icon", children: triggerIcon }), trigger, !triggerIcon && (_jsx("svg", { className: "menu__trigger-arrow", width: "1em", height: "1em", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: _jsx("polyline", { points: "6 9 12 15 18 9" }) }))] }), _jsx("div", { className: `menu__content ${isOpen ? "menu__content--open" : ""}`, role: "menu", children: items.map((item, index) => {
49
+ if (item.divider) {
50
+ return (_jsx("div", { className: "menu__divider", role: "separator" }, `divider-${index}`));
51
+ }
52
+ return (_jsxs("button", { className: `menu__item ${item.checked ? "menu__item--checked" : ""}`.trim(), onClick: () => handleItemClick(item.id), disabled: item.disabled, role: "menuitem", "aria-disabled": item.disabled, children: [item.icon && (_jsx("span", { className: "menu__item-icon", children: item.icon })), _jsx("span", { children: item.label }), hasCheckedItems && item.checked && (_jsx("span", { className: "menu__item-checkmark", role: "presentation", children: "\u2713" }))] }, item.id));
53
+ }) })] }));
54
+ });
55
+ Menu.displayName = "Menu";
56
+ //# sourceMappingURL=Menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Menu.js","sourceRoot":"","sources":["../../src/components/Menu.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import React from "react";
2
+ import "../styles/radiogroup.css";
3
+ export interface RadioOption {
4
+ value: string;
5
+ label: React.ReactNode;
6
+ disabled?: boolean;
7
+ }
8
+ export interface RadioGroupProps {
9
+ /** List of radio options */
10
+ options: RadioOption[];
11
+ /** Currently selected value */
12
+ value?: string;
13
+ /** Called when selection changes */
14
+ onChange?: (value: string) => void;
15
+ /** Group label */
16
+ label?: React.ReactNode;
17
+ /** Group name (for form) */
18
+ name?: string;
19
+ /** Error message */
20
+ error?: string | null;
21
+ /** Helper text */
22
+ description?: React.ReactNode;
23
+ /** Whether the group is required */
24
+ required?: boolean;
25
+ /** Whether all options are disabled */
26
+ disabled?: boolean;
27
+ /** Layout direction for options */
28
+ layout?: 'horizontal' | 'vertical';
29
+ /** Additional class name */
30
+ className?: string;
31
+ }
32
+ /**
33
+ * RadioGroup component matching OpenLearning UI design
34
+ */
35
+ export declare const RadioGroup: React.FC<RadioGroupProps>;
36
+ //# sourceMappingURL=RadioGroup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroup.d.ts","sourceRoot":"","sources":["../../src/components/RadioGroup.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,0BAA0B,CAAC;AAElC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,4BAA4B;IAC5B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,kBAAkB;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,kBAAkB;IAClB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mCAAmC;IACnC,MAAM,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACnC,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CA4DhD,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import "../styles/radiogroup.css";
3
+ /**
4
+ * RadioGroup component matching OpenLearning UI design
5
+ */
6
+ export const RadioGroup = ({ options, value, onChange, label, name, error, description, required, disabled = false, layout = 'horizontal', className = "", }) => {
7
+ const handleChange = (optionValue) => {
8
+ if (!disabled && onChange) {
9
+ onChange(optionValue);
10
+ }
11
+ };
12
+ return (_jsxs("div", { className: `radiogroup-container ${className}`, children: [label && (_jsxs("div", { className: "radiogroup-label", children: [label, required && _jsx("span", { className: "radiogroup-required", children: " *" })] })), _jsx("div", { className: `radiogroup-options radiogroup-options--${layout}`, children: options.map((option, index) => {
13
+ const isDisabled = disabled || option.disabled;
14
+ const isChecked = value === option.value;
15
+ return (_jsxs("label", { className: `radiogroup-option ${isDisabled ? 'radiogroup-option--disabled' : ''} ${index > 0 ? 'radiogroup-option--spaced' : ''}`, children: [_jsx("input", { type: "radio", className: "radiogroup-input", name: name, value: option.value, checked: isChecked, disabled: isDisabled, onChange: () => handleChange(option.value) }), _jsx("div", { className: "radiogroup-radio-container", children: _jsx("div", { className: "radiogroup-radio" }) }), _jsx("span", { className: "radiogroup-option-label", children: option.label })] }, option.value));
16
+ }) }), description && !error && (_jsx("div", { className: "radiogroup-description", children: description })), error && _jsx("div", { className: "radiogroup-error", children: error })] }));
17
+ };
18
+ //# sourceMappingURL=RadioGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadioGroup.js","sourceRoot":"","sources":["../../src/components/RadioGroup.tsx"],"names":[],"mappings":";AACA,OAAO,0BAA0B,CAAC;AAiClC;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAA8B,CAAC,EACpD,OAAO,EACP,KAAK,EACL,QAAQ,EACR,KAAK,EACL,IAAI,EACJ,KAAK,EACL,WAAW,EACX,QAAQ,EACR,QAAQ,GAAG,KAAK,EAChB,MAAM,GAAG,YAAY,EACrB,SAAS,GAAG,EAAE,GACf,EAAE,EAAE;IACH,MAAM,YAAY,GAAG,CAAC,WAAmB,EAAE,EAAE;QAC3C,IAAI,CAAC,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAC1B,QAAQ,CAAC,WAAW,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CACL,eAAK,SAAS,EAAE,wBAAwB,SAAS,EAAE,aAChD,KAAK,IAAI,CACR,eAAK,SAAS,EAAC,kBAAkB,aAC9B,KAAK,EACL,QAAQ,IAAI,eAAM,SAAS,EAAC,qBAAqB,mBAAU,IACxD,CACP,EACD,cAAK,SAAS,EAAE,0CAA0C,MAAM,EAAE,YAC/D,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE;oBAC7B,MAAM,UAAU,GAAG,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC;oBAC/C,MAAM,SAAS,GAAG,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC;oBAEzC,OAAO,CACL,iBAEE,SAAS,EAAE,qBAAqB,UAAU,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,EAAE,EAAE,aAEjI,gBACE,IAAI,EAAC,OAAO,EACZ,SAAS,EAAC,kBAAkB,EAC5B,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,CAAC,KAAK,EACnB,OAAO,EAAE,SAAS,EAClB,QAAQ,EAAE,UAAU,EACpB,QAAQ,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,GAC1C,EACF,cAAK,SAAS,EAAC,4BAA4B,YACzC,cAAK,SAAS,EAAC,kBAAkB,GAAO,GACpC,EACN,eAAM,SAAS,EAAC,yBAAyB,YAAE,MAAM,CAAC,KAAK,GAAQ,KAf1D,MAAM,CAAC,KAAK,CAgBX,CACT,CAAC;gBACJ,CAAC,CAAC,GACE,EACL,WAAW,IAAI,CAAC,KAAK,IAAI,CACxB,cAAK,SAAS,EAAC,wBAAwB,YAAE,WAAW,GAAO,CAC5D,EACA,KAAK,IAAI,cAAK,SAAS,EAAC,kBAAkB,YAAE,KAAK,GAAO,IACrD,CACP,CAAC;AACJ,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ import "../styles/spinner.css";
3
+ export interface SpinnerProps {
4
+ /** Optional label to show next to spinner */
5
+ label?: string;
6
+ /** Color of the spinner (defaults to currentColor) */
7
+ color?: string;
8
+ /** Font size of the spinner icon */
9
+ fontSize?: number;
10
+ }
11
+ /**
12
+ * Loading spinner component matching OpenLearning UI design
13
+ */
14
+ export declare const Spinner: React.FC<SpinnerProps>;
15
+ //# sourceMappingURL=Spinner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Spinner.d.ts","sourceRoot":"","sources":["../../src/components/Spinner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,uBAAuB,CAAC;AAE/B,MAAM,WAAW,YAAY;IAC3B,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,eAAO,MAAM,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAwB1C,CAAC"}