@ndla/ui 55.0.13-alpha.0 → 55.0.14-alpha.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 (297) hide show
  1. package/dist/panda.buildinfo.json +120 -1
  2. package/dist/styles.css +511 -0
  3. package/es/Article/ArticleParagraph.js +11 -13
  4. package/es/CampaignBlock/CampaignBlock.js +103 -68
  5. package/es/Concept/Concept.js +69 -0
  6. package/es/ContentTypeBadge/ContentTypeBadgeNew.js +48 -0
  7. package/es/Embed/AudioEmbed.js +1 -2
  8. package/es/Embed/BrightcoveEmbed.js +13 -24
  9. package/es/Embed/ConceptEmbed.js +57 -301
  10. package/es/Embed/ConceptListEmbed.js +18 -24
  11. package/es/Embed/ContentLinkEmbed.js +10 -10
  12. package/es/Embed/CopyrightEmbed.js +4 -21
  13. package/es/Embed/ExternalEmbed.js +10 -18
  14. package/es/Embed/FootnoteEmbed.js +11 -8
  15. package/es/Embed/GlossEmbed.js +68 -0
  16. package/es/Embed/H5pEmbed.js +19 -19
  17. package/es/Embed/IframeEmbed.js +9 -6
  18. package/es/Embed/InlineTriggerButton.js +70 -0
  19. package/es/Embed/UnknownEmbed.js +9 -9
  20. package/es/Embed/UuDisclaimerEmbed.js +14 -25
  21. package/es/Embed/index.js +1 -3
  22. package/es/ErrorMessage/ErrorMessage.js +41 -22
  23. package/es/ErrorMessage/ErrorResourceAccessDenied.js +8 -6
  24. package/es/FactBox/FactBox.js +118 -47
  25. package/es/FileList/PdfFile.js +23 -5
  26. package/es/Gloss/Gloss.js +116 -86
  27. package/es/Gloss/GlossExample.js +49 -51
  28. package/es/LinkBlock/LinkBlock.js +61 -33
  29. package/es/LinkBlock/LinkBlockSection.js +9 -6
  30. package/es/Logo/Logo.js +1 -30
  31. package/es/RelatedArticleList/RelatedArticleList.js +70 -87
  32. package/es/ResourceBox/ResourceBox.js +65 -37
  33. package/es/TagSelector/TagSelector.js +124 -131
  34. package/es/i18n/index.js +2 -1
  35. package/es/i18n/useComponentTranslations.js +83 -0
  36. package/es/index.js +4 -11
  37. package/es/locale/messages-en.js +30 -4
  38. package/es/locale/messages-nb.js +30 -4
  39. package/es/locale/messages-nn.js +30 -4
  40. package/es/locale/messages-se.js +30 -4
  41. package/es/locale/messages-sma.js +30 -4
  42. package/es/model/ContentType.js +3 -0
  43. package/es/styles.css +511 -0
  44. package/lib/Article/ArticleParagraph.js +12 -14
  45. package/lib/CampaignBlock/CampaignBlock.d.ts +2 -2
  46. package/lib/CampaignBlock/CampaignBlock.js +106 -68
  47. package/lib/Concept/Concept.d.ts +18 -0
  48. package/lib/Concept/Concept.js +75 -0
  49. package/lib/ContentTypeBadge/ContentTypeBadgeNew.d.ts +17 -0
  50. package/lib/ContentTypeBadge/ContentTypeBadgeNew.js +56 -0
  51. package/lib/Embed/AudioEmbed.js +2 -3
  52. package/lib/Embed/BrightcoveEmbed.d.ts +1 -2
  53. package/lib/Embed/BrightcoveEmbed.js +16 -25
  54. package/lib/Embed/ConceptEmbed.d.ts +15 -21
  55. package/lib/Embed/ConceptEmbed.js +58 -301
  56. package/lib/Embed/ConceptListEmbed.js +21 -26
  57. package/lib/Embed/ContentLinkEmbed.js +10 -11
  58. package/lib/Embed/CopyrightEmbed.js +6 -22
  59. package/lib/Embed/ExternalEmbed.d.ts +1 -2
  60. package/lib/Embed/ExternalEmbed.js +13 -19
  61. package/lib/Embed/FootnoteEmbed.js +11 -9
  62. package/lib/Embed/GlossEmbed.d.ts +13 -0
  63. package/lib/Embed/GlossEmbed.js +76 -0
  64. package/lib/Embed/H5pEmbed.d.ts +1 -2
  65. package/lib/Embed/H5pEmbed.js +21 -19
  66. package/lib/Embed/IframeEmbed.d.ts +1 -2
  67. package/lib/Embed/IframeEmbed.js +11 -8
  68. package/lib/Embed/InlineTriggerButton.d.ts +11 -0
  69. package/lib/Embed/InlineTriggerButton.js +76 -0
  70. package/lib/Embed/UnknownEmbed.js +9 -10
  71. package/lib/Embed/UuDisclaimerEmbed.js +16 -26
  72. package/lib/Embed/index.d.ts +2 -3
  73. package/lib/Embed/index.js +2 -9
  74. package/lib/ErrorMessage/ErrorMessage.js +40 -23
  75. package/lib/ErrorMessage/ErrorResourceAccessDenied.js +7 -6
  76. package/lib/FactBox/FactBox.d.ts +0 -1
  77. package/lib/FactBox/FactBox.js +119 -46
  78. package/lib/FileList/PdfFile.js +23 -5
  79. package/lib/Gloss/Gloss.d.ts +10 -2
  80. package/lib/Gloss/Gloss.js +116 -85
  81. package/lib/Gloss/GlossExample.d.ts +3 -5
  82. package/lib/Gloss/GlossExample.js +49 -52
  83. package/lib/LinkBlock/LinkBlock.js +62 -34
  84. package/lib/LinkBlock/LinkBlockSection.js +9 -7
  85. package/lib/Logo/Logo.d.ts +1 -3
  86. package/lib/Logo/Logo.js +2 -30
  87. package/lib/RelatedArticleList/RelatedArticleList.d.ts +4 -4
  88. package/lib/RelatedArticleList/RelatedArticleList.js +74 -90
  89. package/lib/ResourceBox/ResourceBox.js +64 -37
  90. package/lib/TagSelector/TagSelector.d.ts +27 -12
  91. package/lib/TagSelector/TagSelector.js +126 -131
  92. package/lib/i18n/index.d.ts +1 -0
  93. package/lib/i18n/index.js +20 -1
  94. package/lib/i18n/useComponentTranslations.d.ts +14 -0
  95. package/lib/i18n/useComponentTranslations.js +93 -0
  96. package/lib/index.d.ts +5 -14
  97. package/lib/index.js +70 -89
  98. package/lib/locale/messages-en.d.ts +26 -0
  99. package/lib/locale/messages-en.js +30 -4
  100. package/lib/locale/messages-nb.d.ts +26 -0
  101. package/lib/locale/messages-nb.js +30 -4
  102. package/lib/locale/messages-nn.d.ts +26 -0
  103. package/lib/locale/messages-nn.js +30 -4
  104. package/lib/locale/messages-se.d.ts +26 -0
  105. package/lib/locale/messages-se.js +30 -4
  106. package/lib/locale/messages-sma.d.ts +26 -0
  107. package/lib/locale/messages-sma.js +30 -4
  108. package/lib/model/ContentType.d.ts +3 -0
  109. package/lib/model/ContentType.js +4 -1
  110. package/lib/styles.css +511 -0
  111. package/package.json +11 -13
  112. package/src/Article/ArticleParagraph.tsx +11 -9
  113. package/src/CampaignBlock/CampaignBlock.tsx +92 -55
  114. package/src/Concept/Concept.stories.tsx +142 -0
  115. package/src/Concept/Concept.tsx +73 -0
  116. package/src/ContentTypeBadge/ContentTypeBadgeNew.stories.tsx +70 -0
  117. package/src/ContentTypeBadge/ContentTypeBadgeNew.tsx +69 -0
  118. package/src/Embed/AudioEmbed.tsx +2 -2
  119. package/src/Embed/BrightcoveEmbed.stories.tsx +0 -3
  120. package/src/Embed/BrightcoveEmbed.tsx +17 -19
  121. package/src/Embed/ConceptEmbed.stories.tsx +1 -105
  122. package/src/Embed/ConceptEmbed.tsx +60 -385
  123. package/src/Embed/ConceptListEmbed.tsx +20 -19
  124. package/src/Embed/ContentLinkEmbed.tsx +8 -10
  125. package/src/Embed/CopyrightEmbed.tsx +1 -11
  126. package/src/Embed/ExternalEmbed.tsx +14 -17
  127. package/src/Embed/FootnoteEmbed.stories.tsx +2 -5
  128. package/src/Embed/FootnoteEmbed.tsx +13 -16
  129. package/src/Embed/GlossEmbed.stories.tsx +140 -0
  130. package/src/Embed/GlossEmbed.tsx +64 -0
  131. package/src/Embed/H5pEmbed.tsx +22 -16
  132. package/src/Embed/IframeEmbed.tsx +12 -6
  133. package/src/Embed/InlineTriggerButton.tsx +72 -0
  134. package/src/Embed/UnknownEmbed.tsx +6 -7
  135. package/src/Embed/UuDisclaimerEmbed.stories.tsx +4 -4
  136. package/src/Embed/UuDisclaimerEmbed.tsx +17 -25
  137. package/src/Embed/index.ts +2 -3
  138. package/src/ErrorMessage/ErrorMessage.tsx +40 -29
  139. package/src/ErrorMessage/ErrorResourceAccessDenied.tsx +8 -6
  140. package/src/FactBox/FactBox.tsx +115 -115
  141. package/src/FactBox/Factbox.stories.tsx +43 -27
  142. package/src/FileList/FileList.stories.tsx +6 -1
  143. package/src/FileList/PdfFile.tsx +22 -5
  144. package/src/Gloss/Gloss.stories.tsx +107 -1
  145. package/src/Gloss/Gloss.tsx +143 -156
  146. package/src/Gloss/GlossExample.tsx +51 -77
  147. package/src/LinkBlock/LinkBlock.stories.tsx +8 -10
  148. package/src/LinkBlock/LinkBlock.tsx +54 -59
  149. package/src/LinkBlock/LinkBlockSection.tsx +9 -12
  150. package/src/Logo/Logo.stories.tsx +0 -1
  151. package/src/Logo/Logo.tsx +2 -30
  152. package/src/RelatedArticleList/RelatedArticleList.tsx +69 -88
  153. package/src/ResourceBox/ResourceBox.tsx +63 -59
  154. package/src/TagSelector/TagSelector.stories.tsx +92 -68
  155. package/src/TagSelector/TagSelector.tsx +161 -126
  156. package/src/i18n/index.ts +5 -0
  157. package/src/i18n/useComponentTranslations.ts +72 -0
  158. package/src/index.ts +23 -18
  159. package/src/locale/messages-en.ts +28 -2
  160. package/src/locale/messages-nb.ts +28 -2
  161. package/src/locale/messages-nn.ts +28 -2
  162. package/src/locale/messages-se.ts +28 -2
  163. package/src/locale/messages-sma.ts +28 -2
  164. package/src/model/ContentType.ts +3 -0
  165. package/es/DefinitionList/DefinitionDescription.js +0 -28
  166. package/es/DefinitionList/DefinitionTerm.js +0 -28
  167. package/es/DefinitionList/index.js +0 -10
  168. package/es/Embed/conceptComponents.js +0 -155
  169. package/es/ExpandableBox/ExpandableBox.js +0 -29
  170. package/es/ExpandableBox/index.js +0 -9
  171. package/es/Figure/Figure.js +0 -73
  172. package/es/Figure/index.js +0 -9
  173. package/es/FramedContent/FramedContent.js +0 -28
  174. package/es/FramedContent/index.js +0 -10
  175. package/es/Image/Image.js +0 -99
  176. package/es/Image/ImageLink.js +0 -39
  177. package/es/Image/index.js +0 -12
  178. package/es/LetterFilter/LetterFilter.js +0 -54
  179. package/es/LetterFilter/alphabet.js +0 -9
  180. package/es/LetterFilter/index.js +0 -10
  181. package/es/Notion/Notion.js +0 -76
  182. package/es/Notion/NotionImage.js +0 -46
  183. package/es/Notion/index.js +0 -9
  184. package/es/Table/Table.js +0 -141
  185. package/es/Table/index.js +0 -11
  186. package/es/TagSelector/Control.js +0 -28
  187. package/es/TagSelector/DropdownIndicator.js +0 -60
  188. package/es/TagSelector/Input.js +0 -22
  189. package/es/TagSelector/Menu.js +0 -27
  190. package/es/TagSelector/MenuList.js +0 -28
  191. package/es/TagSelector/Option.js +0 -60
  192. package/es/TagSelector/SelectContainer.js +0 -27
  193. package/es/TagSelector/ValueButton.js +0 -53
  194. package/es/TagSelector/ariaMessages.js +0 -94
  195. package/es/TagSelector/index.js +0 -10
  196. package/es/TagSelector/types.js +0 -1
  197. package/lib/DefinitionList/DefinitionDescription.d.ts +0 -10
  198. package/lib/DefinitionList/DefinitionDescription.js +0 -35
  199. package/lib/DefinitionList/DefinitionTerm.d.ts +0 -10
  200. package/lib/DefinitionList/DefinitionTerm.js +0 -35
  201. package/lib/DefinitionList/index.d.ts +0 -9
  202. package/lib/DefinitionList/index.js +0 -20
  203. package/lib/Embed/conceptComponents.d.ts +0 -40
  204. package/lib/Embed/conceptComponents.js +0 -163
  205. package/lib/ExpandableBox/ExpandableBox.d.ts +0 -15
  206. package/lib/ExpandableBox/ExpandableBox.js +0 -37
  207. package/lib/ExpandableBox/index.d.ts +0 -8
  208. package/lib/ExpandableBox/index.js +0 -18
  209. package/lib/Figure/Figure.d.ts +0 -16
  210. package/lib/Figure/Figure.js +0 -81
  211. package/lib/Figure/index.d.ts +0 -9
  212. package/lib/Figure/index.js +0 -13
  213. package/lib/FramedContent/FramedContent.d.ts +0 -12
  214. package/lib/FramedContent/FramedContent.js +0 -35
  215. package/lib/FramedContent/index.d.ts +0 -9
  216. package/lib/FramedContent/index.js +0 -16
  217. package/lib/Image/Image.d.ts +0 -38
  218. package/lib/Image/Image.js +0 -105
  219. package/lib/Image/ImageLink.d.ts +0 -18
  220. package/lib/Image/ImageLink.js +0 -44
  221. package/lib/Image/index.d.ts +0 -12
  222. package/lib/Image/index.js +0 -30
  223. package/lib/LetterFilter/LetterFilter.d.ts +0 -14
  224. package/lib/LetterFilter/LetterFilter.js +0 -61
  225. package/lib/LetterFilter/alphabet.d.ts +0 -8
  226. package/lib/LetterFilter/alphabet.js +0 -15
  227. package/lib/LetterFilter/index.d.ts +0 -9
  228. package/lib/LetterFilter/index.js +0 -16
  229. package/lib/Notion/Notion.d.ts +0 -20
  230. package/lib/Notion/Notion.js +0 -82
  231. package/lib/Notion/NotionImage.d.ts +0 -13
  232. package/lib/Notion/NotionImage.js +0 -54
  233. package/lib/Notion/index.d.ts +0 -8
  234. package/lib/Notion/index.js +0 -13
  235. package/lib/Table/Table.d.ts +0 -19
  236. package/lib/Table/Table.js +0 -145
  237. package/lib/Table/index.d.ts +0 -10
  238. package/lib/Table/index.js +0 -23
  239. package/lib/TagSelector/Control.d.ts +0 -11
  240. package/lib/TagSelector/Control.js +0 -35
  241. package/lib/TagSelector/DropdownIndicator.d.ts +0 -11
  242. package/lib/TagSelector/DropdownIndicator.js +0 -64
  243. package/lib/TagSelector/Input.d.ts +0 -12
  244. package/lib/TagSelector/Input.js +0 -29
  245. package/lib/TagSelector/Menu.d.ts +0 -12
  246. package/lib/TagSelector/Menu.js +0 -34
  247. package/lib/TagSelector/MenuList.d.ts +0 -16
  248. package/lib/TagSelector/MenuList.js +0 -35
  249. package/lib/TagSelector/Option.d.ts +0 -12
  250. package/lib/TagSelector/Option.js +0 -67
  251. package/lib/TagSelector/SelectContainer.d.ts +0 -11
  252. package/lib/TagSelector/SelectContainer.js +0 -34
  253. package/lib/TagSelector/ValueButton.d.ts +0 -20
  254. package/lib/TagSelector/ValueButton.js +0 -60
  255. package/lib/TagSelector/ariaMessages.d.ts +0 -16
  256. package/lib/TagSelector/ariaMessages.js +0 -101
  257. package/lib/TagSelector/index.d.ts +0 -11
  258. package/lib/TagSelector/index.js +0 -13
  259. package/lib/TagSelector/types.d.ts +0 -11
  260. package/lib/TagSelector/types.js +0 -5
  261. package/src/DefinitionList/DefinitionDescription.tsx +0 -26
  262. package/src/DefinitionList/DefinitionTerm.tsx +0 -26
  263. package/src/DefinitionList/index.tsx +0 -10
  264. package/src/Embed/conceptComponents.tsx +0 -293
  265. package/src/ExpandableBox/ExpandableBox.stories.tsx +0 -41
  266. package/src/ExpandableBox/ExpandableBox.tsx +0 -23
  267. package/src/ExpandableBox/index.ts +0 -9
  268. package/src/Figure/Figure.tsx +0 -167
  269. package/src/Figure/index.ts +0 -11
  270. package/src/FramedContent/FramedContent.stories.tsx +0 -152
  271. package/src/FramedContent/FramedContent.tsx +0 -26
  272. package/src/FramedContent/index.ts +0 -10
  273. package/src/Image/Image.stories.tsx +0 -61
  274. package/src/Image/Image.tsx +0 -147
  275. package/src/Image/ImageLink.tsx +0 -37
  276. package/src/Image/index.ts +0 -14
  277. package/src/LetterFilter/LetterFilter.stories.tsx +0 -29
  278. package/src/LetterFilter/LetterFilter.tsx +0 -78
  279. package/src/LetterFilter/alphabet.ts +0 -39
  280. package/src/LetterFilter/index.ts +0 -11
  281. package/src/Notion/Notion.tsx +0 -96
  282. package/src/Notion/NotionImage.tsx +0 -64
  283. package/src/Notion/index.ts +0 -9
  284. package/src/Table/Table.stories.tsx +0 -738
  285. package/src/Table/Table.tsx +0 -284
  286. package/src/Table/index.ts +0 -12
  287. package/src/TagSelector/Control.tsx +0 -34
  288. package/src/TagSelector/DropdownIndicator.tsx +0 -55
  289. package/src/TagSelector/Input.tsx +0 -31
  290. package/src/TagSelector/Menu.tsx +0 -38
  291. package/src/TagSelector/MenuList.tsx +0 -30
  292. package/src/TagSelector/Option.tsx +0 -58
  293. package/src/TagSelector/SelectContainer.tsx +0 -31
  294. package/src/TagSelector/ValueButton.tsx +0 -47
  295. package/src/TagSelector/ariaMessages.ts +0 -96
  296. package/src/TagSelector/index.ts +0 -14
  297. package/src/TagSelector/types.ts +0 -12
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright (c) 2023-present, NDLA.
2
+ * Copyright (c) 2024-present, NDLA.
3
3
  *
4
4
  * This source code is licensed under the GPLv3 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -7,80 +7,104 @@
7
7
  */
8
8
 
9
9
  import { useState } from "react";
10
- import styled from "@emotion/styled";
10
+ import type { ComboboxInputValueChangeDetails } from "@ark-ui/react";
11
+
11
12
  import { Meta, StoryFn } from "@storybook/react";
12
- import TagSelector from "./TagSelector";
13
+ import { Cross } from "@ndla/icons/action";
14
+ import { ChevronDown } from "@ndla/icons/common";
15
+ import { Done } from "@ndla/icons/editor";
16
+ import {
17
+ ComboboxContent,
18
+ ComboboxItem,
19
+ ComboboxItemIndicator,
20
+ ComboboxItemText,
21
+ ComboboxPositioner,
22
+ IconButton,
23
+ Input,
24
+ InputContainer,
25
+ } from "@ndla/primitives";
26
+ import { HStack } from "@ndla/styled-system/jsx";
27
+ import {
28
+ TagSelectorClearTrigger,
29
+ TagSelectorControl,
30
+ TagSelectorInput,
31
+ TagSelectorLabel,
32
+ TagSelectorRoot,
33
+ TagSelectorTrigger,
34
+ } from "./TagSelector";
35
+ import { useTagSelectorTranslations } from "../i18n/useComponentTranslations";
13
36
 
14
- /**
15
- * Komponent for å tagge noe, primært tiltenkt Min NDLA
16
- */
17
37
  export default {
18
- title: "Patterns/TagSelector",
19
- component: TagSelector,
38
+ title: "Components/TagSelector",
39
+ component: TagSelectorRoot,
20
40
  tags: ["autodocs"],
21
- parameters: {
22
- inlineStories: true,
23
- },
24
- argTypes: {
25
- onChange: { control: false },
26
- onCreateTag: { control: false },
27
- tags: { control: false },
28
- selected: { control: false },
29
- },
30
- args: {
31
- label: "Select tags",
32
- labelHidden: false,
33
- },
34
- } as Meta<typeof TagSelector>;
41
+ } satisfies Meta<typeof TagSelectorRoot>;
35
42
 
36
- const Container = styled.div`
37
- margin: 10px auto;
38
- max-width: 600px;
39
- max-height: 300px;
40
- display: flex;
41
- flex-direction: column;
42
- `;
43
+ const data = [
44
+ "BackToSchool",
45
+ "SchoolLife",
46
+ "Homework",
47
+ "SchoolDays",
48
+ "Classroom",
49
+ "StudyTime",
50
+ "TeacherLife",
51
+ "StudentLife",
52
+ "SchoolSpirit",
53
+ "Education",
54
+ ];
43
55
 
44
- export const TagSelectorStory: StoryFn<typeof TagSelector> = (args) => {
45
- const dummyData = [
46
- "Cat",
47
- "Dog",
48
- "Fish",
49
- "Dinosaur",
50
- "Frog",
51
- "Dragon",
52
- "Lion",
53
- "Snake",
54
- "Alligator",
55
- "Antelope",
56
- "Bear",
57
- "Baboon",
58
- "Kangaroo",
59
- "Scorpion",
60
- "Goose",
61
- "Fox",
62
- "Donkey",
63
- "Chicken",
64
- ];
65
- const [exampleTags, setExampleTags] = useState<string[]>(dummyData);
66
- const [exampleTagsSelected, setExampleTagsSelected] = useState<string[]>(dummyData.slice(0, 0));
56
+ export const Default: StoryFn<typeof TagSelectorRoot> = ({ translations, ...args }) => {
57
+ const [options, setOptions] = useState(data);
58
+ const [value, setValue] = useState<string[]>([]);
59
+ const componentTranslations = useTagSelectorTranslations(translations);
60
+
61
+ const handleChange = (e: ComboboxInputValueChangeDetails) => {
62
+ const filtered = data.filter((item) => item.toLowerCase().includes(e.inputValue.toLowerCase()));
63
+ setOptions(filtered);
64
+ };
67
65
 
68
66
  return (
69
- <Container>
70
- <TagSelector
71
- label={args.label}
72
- tags={exampleTags}
73
- selected={exampleTagsSelected}
74
- onChange={(tags: string[]) => {
75
- setExampleTagsSelected(tags);
76
- }}
77
- onCreateTag={(newTagName: string) => {
78
- setExampleTags((prevTags) => [...prevTags, newTagName]);
79
- setExampleTagsSelected((prevSelectedTags) => [...prevSelectedTags, newTagName]);
80
- }}
81
- />
82
- </Container>
67
+ <TagSelectorRoot
68
+ {...args}
69
+ value={value}
70
+ items={options}
71
+ onInputValueChange={handleChange}
72
+ onValueChange={(details) => setValue(details.value)}
73
+ translations={componentTranslations}
74
+ >
75
+ <TagSelectorLabel>Emneknagger</TagSelectorLabel>
76
+ <HStack gap="4xsmall">
77
+ <TagSelectorControl asChild>
78
+ <InputContainer>
79
+ <TagSelectorInput asChild>
80
+ <Input placeholder="Søk etter emneknagger" />
81
+ </TagSelectorInput>
82
+
83
+ <TagSelectorClearTrigger asChild>
84
+ <IconButton variant="clear">
85
+ <Cross />
86
+ </IconButton>
87
+ </TagSelectorClearTrigger>
88
+ </InputContainer>
89
+ </TagSelectorControl>
90
+ <TagSelectorTrigger asChild>
91
+ <IconButton variant="secondary">
92
+ <ChevronDown />
93
+ </IconButton>
94
+ </TagSelectorTrigger>
95
+ </HStack>
96
+ <ComboboxPositioner>
97
+ <ComboboxContent>
98
+ {options.map((item) => (
99
+ <ComboboxItem key={item} item={item}>
100
+ <ComboboxItemText>{item}</ComboboxItemText>
101
+ <ComboboxItemIndicator>
102
+ <Done />
103
+ </ComboboxItemIndicator>
104
+ </ComboboxItem>
105
+ ))}
106
+ </ComboboxContent>
107
+ </ComboboxPositioner>
108
+ </TagSelectorRoot>
83
109
  );
84
110
  };
85
-
86
- TagSelectorStory.storyName = "TagSelect";
@@ -1,142 +1,177 @@
1
1
  /**
2
- * Copyright (c) 2022-present, NDLA.
2
+ * Copyright (c) 2024-present, NDLA.
3
3
  *
4
4
  * This source code is licensed under the GPLv3 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  *
7
7
  */
8
8
 
9
- import { KeyboardEvent, useMemo, useState } from "react";
10
- import { useTranslation } from "react-i18next";
11
- import { MultiValue, StylesConfig } from "react-select";
12
- import CreatableSelect from "react-select/creatable";
13
- import styled from "@emotion/styled";
14
- import { colors, fonts, spacing, utils } from "@ndla/core";
15
- import { createAriaMessages } from "./ariaMessages";
16
- import Control from "./Control";
17
- import DropdownIndicator from "./DropdownIndicator";
18
- import Input from "./Input";
19
- import Menu from "./Menu";
20
- import MenuList from "./MenuList";
21
- import Option from "./Option";
22
- import SelectContainer from "./SelectContainer";
23
- import { TagType } from "./types";
24
- import ValueButton from "./ValueButton";
25
-
26
- const styles: StylesConfig<TagType, true> = {
27
- menu: () => ({}),
28
- dropdownIndicator: () => ({}),
29
- placeholder: (provided) => ({
30
- ...provided,
31
- padding: `0 ${spacing.small}`,
32
- color: colors.brand.primary,
33
- margin: 0,
34
- }),
35
- valueContainer: (provided) => ({ ...provided, padding: 0 }),
36
- indicatorSeparator: () => ({
37
- display: "none",
38
- }),
39
- indicatorsContainer: (provided) => ({
40
- ...provided,
41
- alignSelf: "flex-end",
42
- }),
43
- };
9
+ import { forwardRef, useEffect, useId, useRef } from "react";
10
+ import type { ComboboxCollectionItem } from "@ark-ui/react";
11
+ import { ComboboxContext, useTagsInputContext } from "@ark-ui/react";
12
+ import { Cross } from "@ndla/icons/action";
13
+ import {
14
+ ComboboxClearTrigger,
15
+ ComboboxControl,
16
+ ComboboxControlProps,
17
+ ComboboxInput,
18
+ ComboboxInputProps,
19
+ ComboboxLabel,
20
+ ComboboxRoot,
21
+ ComboboxRootProps,
22
+ ComboboxTrigger,
23
+ TagsInputControl,
24
+ TagsInputControlProps,
25
+ TagsInputInput,
26
+ TagsInputInputProps,
27
+ TagsInputItem,
28
+ TagsInputItemDeleteTrigger,
29
+ TagsInputItemPreview,
30
+ TagsInputItemText,
31
+ TagsInputRoot,
32
+ TagsInputRootProps,
33
+ TagsInputItemInput,
34
+ } from "@ndla/primitives";
35
+ import { contains } from "@ndla/util";
44
36
 
45
- const StyledTagSelector = styled.div`
46
- display: flex;
47
- flex-direction: column;
48
- flex: 1;
49
- overflow: hidden;
50
- `;
51
-
52
- interface StyledLabelProps {
53
- labelHidden?: boolean;
54
- }
55
-
56
- const StyledLabel = styled.label<StyledLabelProps>`
57
- font-weight: ${fonts.weight.semibold};
58
- ${(p) => p.labelHidden && utils.labelHidden}
59
- `;
60
-
61
- interface Props {
62
- label: string;
63
- tags: string[];
64
- selected: string[];
65
- onChange: (tags: string[]) => void;
66
- onCreateTag: (name: string) => void;
67
- className?: string;
68
- labelHidden?: boolean;
69
- }
70
-
71
- const TagSelector = ({
72
- selected: _selected,
73
- tags: _tags,
74
- onChange,
75
- onCreateTag,
76
- className,
77
- label,
78
- labelHidden,
79
- }: Props) => {
80
- const { t } = useTranslation();
81
- const [input, setInput] = useState("");
82
- const tags = useMemo(() => _tags.map((tag) => ({ value: tag, label: tag })), [_tags]);
83
- const selected = useMemo(() => _selected.map((tag) => ({ value: tag, label: tag })), [_selected]);
84
-
85
- const handleSpaceClick = (e: KeyboardEvent<HTMLDivElement>) => {
86
- if (e.key === " ") {
87
- e.preventDefault();
88
- if (!_selected.find((tag) => tag === input) && input !== "") {
89
- onChange(_selected.concat(input));
90
- }
91
- setInput("");
92
- }
93
- };
37
+ export type TagSelectorRootProps<T extends ComboboxCollectionItem> = ComboboxRootProps<T> & TagsInputRootProps;
94
38
 
95
- const handleChange = (tags: MultiValue<TagType>) => {
96
- onChange(tags.map((tag) => tag.value));
39
+ export const TagSelectorRoot = <T extends ComboboxCollectionItem>({
40
+ allowCustomValue = true,
41
+ multiple = true,
42
+ selectionBehavior = "clear",
43
+ editable,
44
+ addOnPaste = false,
45
+ onValueChange,
46
+ children,
47
+ value,
48
+ translations,
49
+ ...rest
50
+ }: TagSelectorRootProps<T>) => {
51
+ const ids = {
52
+ root: useId(),
53
+ input: useId(),
54
+ control: useId(),
97
55
  };
98
56
 
99
- const createLabel = (tag: string) => t("tagSelector.createLabel", { tag });
57
+ const controlRef = useRef<HTMLDivElement | undefined>(undefined);
58
+
59
+ useEffect(() => {
60
+ if (!controlRef.current) {
61
+ controlRef.current = document.getElementById(ids.control) as HTMLDivElement | undefined;
62
+ }
63
+ }, [ids.control]);
100
64
 
101
65
  return (
102
- <StyledTagSelector className={className}>
103
- {label && (
104
- <StyledLabel labelHidden={labelHidden} htmlFor="tagselector-creatable" id="tagselector-label">
105
- {label}
106
- </StyledLabel>
107
- )}
108
- <CreatableSelect
109
- id="tagselector-creatable"
110
- aria-labelledby={label ? "tagselector-label" : undefined}
111
- ariaLiveMessages={createAriaMessages(t)}
112
- components={{
113
- DropdownIndicator,
114
- MultiValue: ValueButton,
115
- SelectContainer,
116
- MenuList,
117
- Control,
118
- Option,
119
- Menu,
120
- Input,
121
- }}
122
- formatCreateLabel={createLabel}
123
- inputValue={input}
124
- isClearable={false}
125
- isMulti
126
- noOptionsMessage={() => t("tagSelector.noOptions")}
127
- onChange={handleChange}
128
- onCreateOption={onCreateTag}
129
- onInputChange={setInput}
130
- onKeyDown={handleSpaceClick}
131
- options={tags}
132
- placeholder={t("tagSelector.placeholder")}
133
- screenReaderStatus={({ count }) => t("tagSelector.aria.screenReaderStatus", { count })}
134
- styles={styles}
135
- tabSelectsValue={false}
136
- value={selected}
137
- />
138
- </StyledTagSelector>
66
+ <ComboboxRoot
67
+ ids={ids}
68
+ asChild
69
+ allowCustomValue={allowCustomValue}
70
+ multiple={multiple}
71
+ selectionBehavior={selectionBehavior}
72
+ onValueChange={onValueChange}
73
+ translations={translations}
74
+ onPointerDownOutside={(event) => {
75
+ if (contains(controlRef.current, event.detail.originalEvent.target)) {
76
+ event.preventDefault();
77
+ }
78
+ }}
79
+ value={value}
80
+ {...rest}
81
+ >
82
+ <ComboboxContext>
83
+ {(api) => (
84
+ <TagsInputRoot
85
+ ids={ids}
86
+ value={value}
87
+ onInputValueChange={(details) => api.setInputValue(details.inputValue)}
88
+ editable={editable}
89
+ onValueChange={onValueChange}
90
+ addOnPaste={addOnPaste}
91
+ translations={translations}
92
+ >
93
+ {children}
94
+ </TagsInputRoot>
95
+ )}
96
+ </ComboboxContext>
97
+ </ComboboxRoot>
139
98
  );
140
99
  };
141
100
 
142
- export default TagSelector;
101
+ export type TagSelectorControlProps = ComboboxControlProps & TagsInputControlProps;
102
+
103
+ export const TagSelectorLabel = ComboboxLabel;
104
+
105
+ export const TagSelectorItemInput = TagsInputItemInput;
106
+
107
+ export const TagSelectorTrigger = ComboboxTrigger;
108
+
109
+ export const TagSelectorControl = forwardRef<HTMLDivElement, TagSelectorControlProps>(({ children, ...props }, ref) => {
110
+ return (
111
+ <ComboboxControl asChild>
112
+ <TagsInputControl {...props} ref={ref}>
113
+ {children}
114
+ </TagsInputControl>
115
+ </ComboboxControl>
116
+ );
117
+ });
118
+
119
+ export const TagSelectorClearTrigger = ComboboxClearTrigger;
120
+
121
+ export type TagSelectorInputProps = ComboboxInputProps & TagsInputInputProps;
122
+
123
+ // If you need to modify the TagsInputItem, you can use this.
124
+ export const TagSelectorInputBase = forwardRef<HTMLInputElement, TagSelectorInputProps>(
125
+ ({ children, ...props }, ref) => {
126
+ const tagsApi = useTagsInputContext();
127
+
128
+ return (
129
+ <ComboboxInput asChild>
130
+ <TagsInputInput
131
+ {...props}
132
+ onKeyDown={(event) => {
133
+ if (event.key === "Enter") {
134
+ tagsApi.addValue(tagsApi.inputValue);
135
+ }
136
+ }}
137
+ ref={ref}
138
+ >
139
+ {children}
140
+ </TagsInputInput>
141
+ </ComboboxInput>
142
+ );
143
+ },
144
+ );
145
+
146
+ export const TagSelectorInput = forwardRef<HTMLInputElement, TagSelectorInputProps>(({ children, ...props }, ref) => {
147
+ const tagsApi = useTagsInputContext();
148
+
149
+ return (
150
+ <>
151
+ {tagsApi.value.map((value, index) => (
152
+ <TagsInputItem index={index} value={value} key={value}>
153
+ <TagsInputItemPreview>
154
+ <TagsInputItemText>{value}</TagsInputItemText>
155
+ <TagsInputItemDeleteTrigger>
156
+ <Cross />
157
+ </TagsInputItemDeleteTrigger>
158
+ </TagsInputItemPreview>
159
+ <TagsInputItemInput />
160
+ </TagsInputItem>
161
+ ))}
162
+ <ComboboxInput asChild>
163
+ <TagsInputInput
164
+ {...props}
165
+ onKeyDown={(event) => {
166
+ if (event.key === "Enter") {
167
+ tagsApi.addValue(tagsApi.inputValue);
168
+ }
169
+ }}
170
+ ref={ref}
171
+ >
172
+ {children}
173
+ </TagsInputInput>
174
+ </ComboboxInput>
175
+ </>
176
+ );
177
+ });
package/src/i18n/index.ts CHANGED
@@ -8,3 +8,8 @@
8
8
 
9
9
  export { i18nInstance } from "./i18n";
10
10
  export { formatNestedMessages } from "./formatNestedMessages";
11
+ export {
12
+ useComboboxTranslations,
13
+ useTagSelectorTranslations,
14
+ useTagsInputTranslations,
15
+ } from "./useComponentTranslations";
@@ -0,0 +1,72 @@
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 { useTranslation } from "react-i18next";
10
+ import type { ComboboxCollectionItem } from "@ark-ui/react";
11
+ import type { ComboboxRootProps, PaginationRootProps, TagsInputRootProps } from "@ndla/primitives";
12
+ import { TagSelectorRootProps } from "../TagSelector/TagSelector";
13
+
14
+ export const useTagsInputTranslations = (
15
+ translations?: Partial<TagsInputRootProps["translations"]>,
16
+ ): TagsInputRootProps["translations"] => {
17
+ const { t } = useTranslation("translation", { keyPrefix: "component.tagsInput" });
18
+
19
+ return {
20
+ clearTriggerLabel: t("clearTriggerLabel"),
21
+ deleteTagTriggerLabel: (tag) => t("deleteTagTriggerLabel", { tag }),
22
+ tagAdded: (tag) => t("tagAdded", { tag }),
23
+ tagsPasted: (tag) => t("tagsPasted", { length: tag.length }),
24
+ tagEdited: (tag) => t("tagEdited", { tag }),
25
+ tagUpdated: (tag) => t("tagUpdated", { tag }),
26
+ tagDeleted: (tag) => t("tagDeleted", { tag }),
27
+ tagSelected: (tag) => t("tagSelected", { tag }),
28
+ ...translations,
29
+ };
30
+ };
31
+
32
+ export const useComboboxTranslations = <T extends ComboboxCollectionItem>(
33
+ translations?: Partial<ComboboxRootProps<T>["translations"]>,
34
+ ): ComboboxRootProps<T>["translations"] => {
35
+ const { t } = useTranslation("translation", { keyPrefix: "component.combobox" });
36
+
37
+ return {
38
+ triggerLabel: t("triggerLabel"),
39
+ clearTriggerLabel: t("clearTriggerLabel"),
40
+ ...translations,
41
+ };
42
+ };
43
+
44
+ export const useTagSelectorTranslations = <T extends ComboboxCollectionItem>(
45
+ translations?: Partial<TagSelectorRootProps<T>["translations"]>,
46
+ ): TagSelectorRootProps<T>["translations"] => {
47
+ const tagsInputTranslations = useTagsInputTranslations();
48
+ const comboboxTranslations = useComboboxTranslations();
49
+
50
+ return {
51
+ ...comboboxTranslations,
52
+ ...tagsInputTranslations,
53
+ ...translations,
54
+ } as TagSelectorRootProps<T>["translations"];
55
+ };
56
+
57
+ export const usePaginationTranslations = (
58
+ translations?: Partial<PaginationRootProps["translations"]>,
59
+ ): PaginationRootProps["translations"] => {
60
+ const { t } = useTranslation("translation", { keyPrefix: "component.pagination" });
61
+
62
+ return {
63
+ rootLabel: t("rootLabel"),
64
+ prevTriggerLabel: t("prevTriggerLabel"),
65
+ nextTriggerLabel: t("nextTriggerLabel"),
66
+ itemLabel: (details) => {
67
+ const lastPage = details.totalPages > 1 && details.page === details.totalPages;
68
+ return lastPage ? t("lastPage", { page: details.page }) : t("page", { page: details.page });
69
+ },
70
+ ...translations,
71
+ };
72
+ };
package/src/index.ts CHANGED
@@ -9,10 +9,7 @@
9
9
  // Ignore typescript implicit any warning and export all javascript components
10
10
  // Move components to this file when they are migrated to typescript
11
11
 
12
- export { ExpandableBox, ExpandableBoxSummary } from "./ExpandableBox";
13
- export { default as FramedContent } from "./FramedContent";
14
12
  export {
15
- ConceptNotionV2,
16
13
  ImageEmbed,
17
14
  getCrop,
18
15
  getFocalPoint,
@@ -51,8 +48,6 @@ export type { ArticleModifier } from "./Article";
51
48
 
52
49
  export { getPossiblyRelativeUrl } from "./utils/relativeUrl";
53
50
 
54
- export { default as Table, TableStyling } from "./Table";
55
-
56
51
  export { default as ContentLoader } from "./ContentLoader";
57
52
 
58
53
  export { default as RelatedArticleList, RelatedArticle } from "./RelatedArticleList";
@@ -65,9 +60,6 @@ export { default as Logo } from "./Logo";
65
60
 
66
61
  export { default as FactBox } from "./FactBox";
67
62
 
68
- export { default as Image, ImageLink, makeSrcQueryString } from "./Image";
69
- export type { ImageCrop, ImageFocalPoint } from "./Image";
70
-
71
63
  export type { HeroContentType } from "./Hero";
72
64
  export {
73
65
  SubjectMaterialHero,
@@ -83,9 +75,6 @@ export {
83
75
 
84
76
  export { FooterBlock } from "./Footer";
85
77
 
86
- export { Figure } from "./Figure";
87
- export type { FigureType } from "./Figure";
88
-
89
78
  export { LanguageSelector } from "./LanguageSelector";
90
79
 
91
80
  export { default as SearchResultSleeve } from "./Search/SearchResultSleeve";
@@ -115,7 +104,13 @@ export { default as messagesSMA } from "./locale/messages-sma";
115
104
  export { default as Breadcrumb, HomeBreadcrumb } from "./Breadcrumb";
116
105
  export type { SimpleBreadcrumbItem, IndexedBreadcrumbItem } from "./Breadcrumb";
117
106
 
118
- export { i18nInstance, formatNestedMessages } from "./i18n";
107
+ export {
108
+ i18nInstance,
109
+ formatNestedMessages,
110
+ useTagsInputTranslations,
111
+ useTagSelectorTranslations,
112
+ useComboboxTranslations,
113
+ } from "./i18n";
119
114
 
120
115
  export { default as LayoutItem, OneColumn, PageContainer } from "./Layout";
121
116
 
@@ -130,14 +125,26 @@ export {
130
125
  ConceptBadge,
131
126
  } from "./ContentTypeBadge";
132
127
 
128
+ export type { ContentTypeBadgeProps } from "./ContentTypeBadge/ContentTypeBadgeNew";
129
+ export {
130
+ ContentTypeBadge as ContentTypeBadgeNew,
131
+ contentTypeToBadgeVariantMap,
132
+ } from "./ContentTypeBadge/ContentTypeBadgeNew";
133
+
133
134
  export { default as CopyParagraphButton } from "./CopyParagraphButton";
134
135
 
135
136
  export { default as ContentPlaceholder } from "./ContentPlaceholder";
136
137
 
137
- export { Notion } from "./Notion";
138
-
139
- export type { TagType } from "./TagSelector";
140
- export { TagSelector } from "./TagSelector";
138
+ export {
139
+ TagSelectorRoot,
140
+ TagSelectorLabel,
141
+ TagSelectorItemInput,
142
+ TagSelectorTrigger,
143
+ TagSelectorControl,
144
+ TagSelectorClearTrigger,
145
+ TagSelectorInputBase,
146
+ TagSelectorInput,
147
+ } from "./TagSelector/TagSelector";
141
148
 
142
149
  export { SnackbarProvider, useSnack, BaseSnack, DefaultSnackbar } from "./SnackBar";
143
150
  export type { Snack, SnackContext } from "./SnackBar";
@@ -145,7 +152,6 @@ export { TreeStructure } from "./TreeStructure";
145
152
  export type { TreeStructureProps } from "./TreeStructure";
146
153
 
147
154
  export { SearchField, SearchResultList, SearchResultItem, ActiveFilters } from "./Search";
148
- export { default as LetterFilter } from "./LetterFilter";
149
155
 
150
156
  export { OrderedList, UnOrderedList } from "./List";
151
157
  export { BlogPostV2 } from "./BlogPost";
@@ -162,7 +168,6 @@ export {
162
168
  FRONTPAGE_ARTICLE_MAX_WIDTH,
163
169
  WIDE_FRONTPAGE_ARTICLE_MAX_WIDTH,
164
170
  } from "./FrontpageArticle";
165
- export { DefinitionTerm, DefinitionDescription } from "./DefinitionList";
166
171
  export type { ProgrammeV2 } from "./ProgrammeCard";
167
172
 
168
173
  export { Gloss, GlossExample } from "./Gloss";