@ndla/primitives 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.
Files changed (97) hide show
  1. package/LICENSE +674 -0
  2. package/dist/panda.buildinfo.json +426 -0
  3. package/dist/styles.css +1738 -0
  4. package/es/Accordion.js +103 -0
  5. package/es/ArticleLists.js +106 -0
  6. package/es/Badge.js +55 -0
  7. package/es/BlockQuote.js +49 -0
  8. package/es/Button.js +211 -0
  9. package/es/Checkbox.js +118 -0
  10. package/es/Dialog.js +329 -0
  11. package/es/ExpandableBox.js +55 -0
  12. package/es/FieldErrorMessage.js +44 -0
  13. package/es/FieldHelper.js +37 -0
  14. package/es/FormControl.js +163 -0
  15. package/es/FramedContent.js +54 -0
  16. package/es/Icon.js +71 -0
  17. package/es/Input.js +159 -0
  18. package/es/Label.js +104 -0
  19. package/es/Menu.js +171 -0
  20. package/es/MessageBox.js +57 -0
  21. package/es/NdlaLogo.js +284 -0
  22. package/es/Pagination.js +37 -0
  23. package/es/Popover.js +78 -0
  24. package/es/RadioGroup.js +136 -0
  25. package/es/Skeleton.js +31 -0
  26. package/es/Slider.js +102 -0
  27. package/es/Spinner.js +54 -0
  28. package/es/Switch.js +130 -0
  29. package/es/Table.js +75 -0
  30. package/es/Text.js +54 -0
  31. package/es/Toast.js +82 -0
  32. package/es/Tooltip.js +59 -0
  33. package/es/createStyleContext.js +62 -0
  34. package/es/index.js +19 -0
  35. package/lib/Accordion.d.ts +17 -0
  36. package/lib/Accordion.js +109 -0
  37. package/lib/ArticleLists.d.ts +20 -0
  38. package/lib/ArticleLists.js +115 -0
  39. package/lib/Badge.d.ts +33 -0
  40. package/lib/Badge.js +62 -0
  41. package/lib/BlockQuote.d.ts +28 -0
  42. package/lib/BlockQuote.js +56 -0
  43. package/lib/Button.d.ts +131 -0
  44. package/lib/Button.js +217 -0
  45. package/lib/Checkbox.d.ts +15 -0
  46. package/lib/Checkbox.js +125 -0
  47. package/lib/Dialog.d.ts +107 -0
  48. package/lib/Dialog.js +338 -0
  49. package/lib/ExpandableBox.d.ts +12 -0
  50. package/lib/ExpandableBox.js +63 -0
  51. package/lib/FieldErrorMessage.d.ts +11 -0
  52. package/lib/FieldErrorMessage.js +50 -0
  53. package/lib/FieldHelper.d.ts +11 -0
  54. package/lib/FieldHelper.js +43 -0
  55. package/lib/FormControl.d.ts +65 -0
  56. package/lib/FormControl.js +173 -0
  57. package/lib/FramedContent.d.ts +32 -0
  58. package/lib/FramedContent.js +61 -0
  59. package/lib/Icon.d.ts +37 -0
  60. package/lib/Icon.js +78 -0
  61. package/lib/Input.d.ts +20 -0
  62. package/lib/Input.js +165 -0
  63. package/lib/Label.d.ts +16 -0
  64. package/lib/Label.js +110 -0
  65. package/lib/Menu.d.ts +25 -0
  66. package/lib/Menu.js +179 -0
  67. package/lib/MessageBox.d.ts +33 -0
  68. package/lib/MessageBox.js +64 -0
  69. package/lib/NdlaLogo.d.ts +15 -0
  70. package/lib/NdlaLogo.js +293 -0
  71. package/lib/Pagination.d.ts +14 -0
  72. package/lib/Pagination.js +43 -0
  73. package/lib/Popover.d.ts +22 -0
  74. package/lib/Popover.js +87 -0
  75. package/lib/RadioGroup.d.ts +19 -0
  76. package/lib/RadioGroup.js +143 -0
  77. package/lib/Skeleton.d.ts +11 -0
  78. package/lib/Skeleton.js +38 -0
  79. package/lib/Slider.d.ts +17 -0
  80. package/lib/Slider.js +109 -0
  81. package/lib/Spinner.d.ts +26 -0
  82. package/lib/Spinner.js +61 -0
  83. package/lib/Switch.d.ts +21 -0
  84. package/lib/Switch.js +137 -0
  85. package/lib/Table.d.ts +10 -0
  86. package/lib/Table.js +82 -0
  87. package/lib/Text.d.ts +24 -0
  88. package/lib/Text.js +62 -0
  89. package/lib/Toast.d.ts +18 -0
  90. package/lib/Toast.js +90 -0
  91. package/lib/Tooltip.d.ts +16 -0
  92. package/lib/Tooltip.js +65 -0
  93. package/lib/createStyleContext.d.ts +27 -0
  94. package/lib/createStyleContext.js +69 -0
  95. package/lib/index.d.ts +28 -0
  96. package/lib/index.js +130 -0
  97. package/package.json +48 -0
package/es/Icon.js ADDED
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Copyright (c) 2024-present, NDLA.
3
+ *
4
+ * This source code is licensed under the GPLv3 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import { cva, cx } from "@ndla/styled-system/css";
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ export const iconRecipe = cva({
12
+ base: {
13
+ display: "inline-block",
14
+ fill: "currentcolor",
15
+ verticalAlign: "middle",
16
+ lineHeight: "1em",
17
+ flexShrink: "0"
18
+ },
19
+ defaultVariants: {
20
+ size: "medium"
21
+ },
22
+ variants: {
23
+ size: {
24
+ xsmall: {
25
+ width: "xsmall",
26
+ height: "xsmall"
27
+ },
28
+ small: {
29
+ width: "small",
30
+ height: "small"
31
+ },
32
+ medium: {
33
+ width: "medium",
34
+ height: "medium"
35
+ },
36
+ large: {
37
+ width: "large",
38
+ height: "large"
39
+ }
40
+ }
41
+ }
42
+ });
43
+ // TODO: Move this component over to ndla/icons
44
+ export const Icon = _ref => {
45
+ let {
46
+ children,
47
+ size,
48
+ role,
49
+ title,
50
+ description,
51
+ width,
52
+ height,
53
+ className,
54
+ "aria-hidden": ariaHidden = true,
55
+ ...props
56
+ } = _ref;
57
+ return /*#__PURE__*/_jsxs("svg", {
58
+ "data-icon": "",
59
+ "aria-hidden": ariaHidden,
60
+ preserveAspectRatio: "xMidYMid meet",
61
+ ...props,
62
+ className: cx(iconRecipe({
63
+ size
64
+ }), className),
65
+ children: [title && /*#__PURE__*/_jsx("title", {
66
+ children: title
67
+ }), description && /*#__PURE__*/_jsx("desc", {
68
+ children: description
69
+ }), children]
70
+ });
71
+ };
package/es/Input.js ADDED
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Copyright (c) 2024-present, NDLA.
3
+ *
4
+ * This source code is licensed under the GPLv3 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import { createContext, forwardRef, useCallback, useContext, useEffect, useRef } from "react";
10
+ import { css, cx } from "@ndla/styled-system/css";
11
+ import { styled } from "@ndla/styled-system/jsx";
12
+ import { composeRefs } from "@ndla/util";
13
+ import { useFormControl } from "./FormControl";
14
+ import { jsx as _jsx } from "react/jsx-runtime";
15
+ const InputContext = /*#__PURE__*/createContext(undefined);
16
+ const inputCss = css.raw({
17
+ outline: "1px solid",
18
+ outlineColor: "stroke.subtle",
19
+ background: "background.default",
20
+ borderRadius: "xsmall",
21
+ minHeight: "xxlarge",
22
+ paddingBlock: "0",
23
+ paddingInline: "xsmall",
24
+ _ariaInvalid: {
25
+ outlineColor: "stroke.error",
26
+ _hover: {
27
+ outlineColor: "stroke.error"
28
+ },
29
+ _focusWithin: {
30
+ outlineColor: "stroke.error",
31
+ _hover: {
32
+ outlineColor: "stroke.error"
33
+ }
34
+ }
35
+ },
36
+ _hover: {
37
+ outlineColor: "stroke.hover"
38
+ },
39
+ _focusWithin: {
40
+ outlineWidth: "2px",
41
+ outlineOffset: "-1px",
42
+ outlineColor: "stroke.default",
43
+ _hover: {
44
+ outlineColor: "stroke.default"
45
+ }
46
+ },
47
+ "&:disabled, &:has(:disabled)": {
48
+ outlineColor: "stroke.subtle",
49
+ _hover: {
50
+ outlineColor: "stroke.subtle"
51
+ }
52
+ }
53
+ });
54
+ const StyledInputContainer = styled("div", {
55
+ base: {
56
+ width: "100%",
57
+ display: "flex",
58
+ alignItems: "center",
59
+ "& svg": {
60
+ width: "medium",
61
+ height: "medium"
62
+ }
63
+ }
64
+ });
65
+ export const InputContainer = /*#__PURE__*/forwardRef((_ref, ref) => {
66
+ let {
67
+ children,
68
+ className,
69
+ ...rest
70
+ } = _ref;
71
+ return /*#__PURE__*/_jsx(InputContext.Provider, {
72
+ value: {},
73
+ children: /*#__PURE__*/_jsx(StyledInputContainer, {
74
+ className: cx(css(inputCss), className),
75
+ ...rest,
76
+ ref: ref,
77
+ children: children
78
+ })
79
+ });
80
+ });
81
+ const baseInputCss = css.raw({
82
+ width: "100%",
83
+ color: "text.default",
84
+ outline: "none",
85
+ background: "none",
86
+ border: "0",
87
+ padding: "xxsmall",
88
+ _disabled: {
89
+ cursor: "not-allowed"
90
+ },
91
+ // Chrome messes with input styling when autofilling. Having a really long transitions cancels this out.
92
+ _autofill: {
93
+ transition: "background-color 600000s 0s, color 600000s 0s"
94
+ },
95
+ _focus: {
96
+ appearance: "none"
97
+ }
98
+ });
99
+ const baseTextAreaCss = css.raw({
100
+ paddingInline: "xsmall",
101
+ paddingBlock: "xsmall",
102
+ resize: "none",
103
+ overflowY: "hidden"
104
+ });
105
+ export const Input = /*#__PURE__*/forwardRef((_ref2, ref) => {
106
+ let {
107
+ className,
108
+ ...props
109
+ } = _ref2;
110
+ const context = useContext(InputContext);
111
+ return /*#__PURE__*/_jsx(styled.input, {
112
+ className: cx(css(baseInputCss, context ? undefined : inputCss), className),
113
+ ref: ref,
114
+ ...props
115
+ });
116
+ });
117
+ export const FormInput = /*#__PURE__*/forwardRef((props, ref) => {
118
+ const field = useFormControl(props);
119
+ return /*#__PURE__*/_jsx(Input, {
120
+ ...field,
121
+ ref: ref
122
+ });
123
+ });
124
+ export const TextArea = /*#__PURE__*/forwardRef((_ref3, ref) => {
125
+ let {
126
+ className,
127
+ ...props
128
+ } = _ref3;
129
+ const context = useContext(InputContext);
130
+ const localRef = useRef(null);
131
+
132
+ // Automatically resize a textarea based on its content
133
+ const resize = useCallback(() => {
134
+ if (!localRef.current) return;
135
+ localRef.current.style.height = "0";
136
+ localRef.current.style.height = "".concat(localRef.current.scrollHeight + 3, "px");
137
+ }, []);
138
+ useEffect(() => {
139
+ window.addEventListener("input", resize);
140
+ window.addEventListener("resize", resize);
141
+ resize();
142
+ return () => {
143
+ window.removeEventListener("input", resize);
144
+ window.removeEventListener("resize", resize);
145
+ };
146
+ }, [resize]);
147
+ return /*#__PURE__*/_jsx(styled.textarea, {
148
+ className: cx(css(baseInputCss, context ? undefined : inputCss, baseTextAreaCss), className),
149
+ ref: composeRefs(ref, localRef),
150
+ ...props
151
+ });
152
+ });
153
+ export const FormTextArea = /*#__PURE__*/forwardRef((props, ref) => {
154
+ const field = useFormControl(props);
155
+ return /*#__PURE__*/_jsx(TextArea, {
156
+ ...field,
157
+ ref: ref
158
+ });
159
+ });
package/es/Label.js ADDED
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Copyright (c) 2024-present, NDLA.
3
+ *
4
+ * This source code is licensed under the GPLv3 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import { forwardRef } from "react";
10
+ import { css, cx } from "@ndla/styled-system/css";
11
+ import { styled } from "@ndla/styled-system/jsx";
12
+ import { useFormControlContext } from "./FormControl";
13
+ import { jsx as _jsx } from "react/jsx-runtime";
14
+ const StyledLegend = styled("legend", {
15
+ base: {
16
+ float: "none",
17
+ width: "inherit",
18
+ _disabled: {
19
+ color: "text.subtle"
20
+ }
21
+ }
22
+ });
23
+ export const Legend = /*#__PURE__*/forwardRef((_ref, ref) => {
24
+ let {
25
+ textStyle = "label.medium",
26
+ fontWeight = "bold",
27
+ className,
28
+ srOnly,
29
+ ...rest
30
+ } = _ref;
31
+ return /*#__PURE__*/_jsx(StyledLegend, {
32
+ className: cx(css({
33
+ textStyle,
34
+ fontWeight,
35
+ srOnly
36
+ }), className),
37
+ ...rest,
38
+ ref: ref
39
+ });
40
+ });
41
+ export const FormLegend = /*#__PURE__*/forwardRef((props, ref) => {
42
+ var _control$getLabelProp;
43
+ const control = useFormControlContext();
44
+ // Legend does not use htmlFor (for), so we remove it.
45
+ const {
46
+ id: _,
47
+ htmlFor: __,
48
+ ...fieldProps
49
+ } = (_control$getLabelProp = control === null || control === void 0 ? void 0 : control.getLabelProps(props, ref)) !== null && _control$getLabelProp !== void 0 ? _control$getLabelProp : {
50
+ ref,
51
+ ...props
52
+ };
53
+ return /*#__PURE__*/_jsx(Legend, {
54
+ ...props,
55
+ ...fieldProps,
56
+ ref: ref
57
+ });
58
+ });
59
+ const StyledLabel = styled("label", {
60
+ base: {
61
+ display: "inline-block",
62
+ _disabled: {
63
+ color: "text.subtle"
64
+ }
65
+ }
66
+ });
67
+ export const Label = /*#__PURE__*/forwardRef((_ref2, ref) => {
68
+ let {
69
+ textStyle = "label.medium",
70
+ fontWeight = "bold",
71
+ className,
72
+ srOnly,
73
+ ...rest
74
+ } = _ref2;
75
+ return /*#__PURE__*/_jsx(StyledLabel, {
76
+ className: cx(css({
77
+ textStyle,
78
+ fontWeight,
79
+ srOnly
80
+ }), className),
81
+ ...rest,
82
+ ref: ref
83
+ });
84
+ });
85
+ export const FormLabel = /*#__PURE__*/forwardRef((props, ref) => {
86
+ var _control$getLabelProp2;
87
+ const control = useFormControlContext();
88
+ const fieldProps = (_control$getLabelProp2 = control === null || control === void 0 ? void 0 : control.getLabelProps(props, ref)) !== null && _control$getLabelProp2 !== void 0 ? _control$getLabelProp2 : {
89
+ ref,
90
+ ...props
91
+ };
92
+ return /*#__PURE__*/_jsx(Label, {
93
+ ...props,
94
+ ...fieldProps,
95
+ ref: ref
96
+ });
97
+ });
98
+ export const Fieldset = styled("fieldset", {
99
+ base: {
100
+ border: "none",
101
+ padding: "0",
102
+ margin: "0"
103
+ }
104
+ });
package/es/Menu.js ADDED
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Copyright (c) 2024-present, NDLA.
3
+ *
4
+ * This source code is licensed under the GPLv3 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import { menuAnatomy } from "@ark-ui/anatomy";
10
+ import { Menu } from "@ark-ui/react";
11
+ import { cva, sva } from "@ndla/styled-system/css";
12
+ import { styled } from "@ndla/styled-system/jsx";
13
+ import { createStyleContext } from "./createStyleContext";
14
+ import { Text } from "./Text";
15
+ import { jsx as _jsx } from "react/jsx-runtime";
16
+ const itemStyle = {
17
+ display: "flex",
18
+ alignItems: "center",
19
+ borderRadius: "xsmall",
20
+ cursor: "pointer",
21
+ textStyle: "label.medium",
22
+ paddingBlock: "4xsmall",
23
+ paddingInline: "xsmall",
24
+ gap: "xsmall",
25
+ transitionDuration: "fast",
26
+ transitionProperty: "background, color",
27
+ transitionTimingFunction: "default",
28
+ outline: "none",
29
+ _hover: {
30
+ textDecoration: "underline"
31
+ },
32
+ _highlighted: {
33
+ textDecoration: "underline"
34
+ },
35
+ _disabled: {
36
+ color: "text.disabled",
37
+ cursor: "not-allowed",
38
+ "& svg": {
39
+ color: "stroke.disabled"
40
+ },
41
+ _hover: {
42
+ color: "text.disabled",
43
+ textDecoration: "none",
44
+ background: "surface.default",
45
+ "& svg": {
46
+ color: "stroke.disabled"
47
+ }
48
+ }
49
+ }
50
+ };
51
+ const itemCva = cva({
52
+ defaultVariants: {
53
+ variant: "action"
54
+ },
55
+ variants: {
56
+ variant: {
57
+ action: {
58
+ _hover: {
59
+ background: "surface.hover"
60
+ },
61
+ _highlighted: {
62
+ background: "surface.hover"
63
+ },
64
+ _active: {
65
+ background: "surface.active"
66
+ }
67
+ },
68
+ destructive: {
69
+ color: "text.error",
70
+ "& svg": {
71
+ color: "icon.error"
72
+ },
73
+ _hover: {
74
+ color: "text.default",
75
+ "& svg": {
76
+ color: "icon.default"
77
+ },
78
+ background: "surface.errorSubtle.hover"
79
+ },
80
+ _highlighted: {
81
+ color: "text.default",
82
+ "& svg": {
83
+ color: "icon.default"
84
+ },
85
+ background: "surface.errorSubtle.hover"
86
+ },
87
+ _active: {
88
+ background: "surface.errorSubtle.active"
89
+ }
90
+ }
91
+ }
92
+ }
93
+ });
94
+ const menuRecipe = sva({
95
+ slots: menuAnatomy.keys(),
96
+ base: {
97
+ item: itemStyle,
98
+ triggerItem: itemStyle,
99
+ content: {
100
+ display: "flex",
101
+ flexDirection: "column",
102
+ width: "fit-content",
103
+ minWidth: "surface.xxsmall",
104
+ padding: "3xsmall",
105
+ gap: "3xsmall",
106
+ background: "surface.default",
107
+ boxShadow: "xsmall",
108
+ borderRadius: "xsmall",
109
+ outline: "none",
110
+ zIndex: "dropdown",
111
+ _open: {
112
+ animation: "fade-shift-in 0.25s ease-out"
113
+ },
114
+ _closed: {
115
+ animation: "fade-shift-out 0.25s ease-out"
116
+ }
117
+ },
118
+ itemGroup: {
119
+ display: "flex",
120
+ flexDirection: "column",
121
+ gap: "3xsmall"
122
+ },
123
+ positioner: {
124
+ zIndex: "dropdown"
125
+ }
126
+ }
127
+ });
128
+ const {
129
+ withRootProvider,
130
+ withContext
131
+ } = createStyleContext(menuRecipe);
132
+ const InternalMenuRoot = withRootProvider(Menu.Root);
133
+ export const MenuRoot = _ref => {
134
+ let {
135
+ lazyMount = true,
136
+ unmountOnExit = true,
137
+ ...props
138
+ } = _ref;
139
+ return /*#__PURE__*/_jsx(InternalMenuRoot, {
140
+ lazyMount: lazyMount,
141
+ unmountOnExit: unmountOnExit,
142
+ ...props
143
+ });
144
+ };
145
+ export const MenuContent = withContext(Menu.Content, "content");
146
+ const InternalMenuItemGroupLabel = withContext(Menu.ItemGroupLabel, "itemGroupLabel");
147
+ export const MenuItemGroupLabel = _ref2 => {
148
+ let {
149
+ textStyle = "label.medium",
150
+ fontWeight = "bold",
151
+ children,
152
+ ...props
153
+ } = _ref2;
154
+ return /*#__PURE__*/_jsx(InternalMenuItemGroupLabel, {
155
+ ...props,
156
+ asChild: true,
157
+ children: /*#__PURE__*/_jsx(Text, {
158
+ textStyle: textStyle,
159
+ fontWeight: fontWeight,
160
+ children: children
161
+ })
162
+ });
163
+ };
164
+ export const MenuItemGroup = withContext(Menu.ItemGroup, "itemGroup");
165
+ const InternalMenuItem = withContext(Menu.Item, "item");
166
+ export const MenuItem = styled(InternalMenuItem, itemCva);
167
+ export const MenuPositioner = withContext(Menu.Positioner, "positioner");
168
+ const InternalMenuTriggerItem = withContext(Menu.TriggerItem, "triggerItem");
169
+ export const MenuTriggerItem = styled(InternalMenuTriggerItem, itemCva);
170
+ export const MenuTrigger = withContext(Menu.Trigger, "trigger");
171
+ export const MenuSeparator = withContext(Menu.Separator, "separator");
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Copyright (c) 2024-present, NDLA.
3
+ *
4
+ * This source code is licensed under the GPLv3 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import { cva, cx } from "@ndla/styled-system/css";
10
+ import { styled } from "@ndla/styled-system/jsx";
11
+ import { jsx as _jsx } from "react/jsx-runtime";
12
+ const messageBoxRecipe = cva({
13
+ base: {
14
+ display: "flex",
15
+ alignItems: "flex-start",
16
+ gap: "small",
17
+ padding: "medium",
18
+ border: "1px solid",
19
+ borderRadius: "xsmall"
20
+ },
21
+ defaultVariants: {
22
+ variant: "info"
23
+ },
24
+ variants: {
25
+ variant: {
26
+ info: {
27
+ background: "surface.infoSubtle",
28
+ borderColor: "stroke.subtle"
29
+ },
30
+ warning: {
31
+ background: "surface.warningSubtle",
32
+ borderColor: "stroke.warning"
33
+ },
34
+ success: {
35
+ background: "surface.successSubtle",
36
+ borderColor: "stroke.success"
37
+ },
38
+ error: {
39
+ background: "surface.errorSubtle",
40
+ borderColor: "stroke.error"
41
+ }
42
+ }
43
+ }
44
+ });
45
+ export const MessageBox = _ref => {
46
+ let {
47
+ className,
48
+ variant,
49
+ ...rest
50
+ } = _ref;
51
+ return /*#__PURE__*/_jsx(styled.div, {
52
+ className: cx(messageBoxRecipe({
53
+ variant
54
+ }), className),
55
+ ...rest
56
+ });
57
+ };