jvetrau-ds 0.2.47 → 0.2.49

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 (93) hide show
  1. package/components/course-outline/course-outline.cjs +54 -41
  2. package/components/course-outline/course-outline.cjs.map +1 -1
  3. package/components/course-outline/course-outline.css +56 -3
  4. package/components/course-outline/course-outline.d.ts +4 -0
  5. package/components/course-outline/course-outline.js +52 -42
  6. package/components/course-outline/course-outline.js.map +1 -1
  7. package/components/course-outline/index.cjs +10 -1
  8. package/components/course-outline/index.d.ts +2 -2
  9. package/components/course-outline/index.js +1 -1
  10. package/components/dropdown/dropdown.cjs +34 -5
  11. package/components/dropdown/dropdown.cjs.map +1 -1
  12. package/components/dropdown/dropdown.js +34 -5
  13. package/components/dropdown/dropdown.js.map +1 -1
  14. package/components/index.cjs +4 -0
  15. package/components/index.d.ts +3 -3
  16. package/components/index.js +1 -1
  17. package/components/markdown/index.d.ts +1 -1
  18. package/components/markdown/markdown.cjs +13 -2
  19. package/components/markdown/markdown.cjs.map +1 -1
  20. package/components/markdown/markdown.d.ts +2 -0
  21. package/components/markdown/markdown.js +13 -2
  22. package/components/markdown/markdown.js.map +1 -1
  23. package/index.cjs +4 -0
  24. package/index.d.ts +3 -3
  25. package/index.js +1 -1
  26. package/layouts/base/base.css +1 -1
  27. package/package.json +1 -1
  28. package/styles.css +57 -4
  29. package/themes/base/desktop.css +1 -1
  30. package/themes/base/desktop.md +1 -1
  31. package/themes/base/desktop.scoped.css +1 -1
  32. package/themes/base/diagram.css +1 -1
  33. package/themes/base/diagram.md +1 -1
  34. package/themes/base/diagram.scoped.css +1 -1
  35. package/themes/base/mobile.css +1 -1
  36. package/themes/base/mobile.md +1 -1
  37. package/themes/base/mobile.scoped.css +1 -1
  38. package/themes/base/responsive.css +2 -2
  39. package/themes/brandcopilot/desktop.css +1 -1
  40. package/themes/brandcopilot/desktop.md +1 -1
  41. package/themes/brandcopilot/desktop.scoped.css +1 -1
  42. package/themes/brandcopilot/diagram.css +1 -1
  43. package/themes/brandcopilot/diagram.md +1 -1
  44. package/themes/brandcopilot/diagram.scoped.css +1 -1
  45. package/themes/brandcopilot/mobile.css +1 -1
  46. package/themes/brandcopilot/mobile.md +1 -1
  47. package/themes/brandcopilot/mobile.scoped.css +1 -1
  48. package/themes/brandcopilot/responsive.css +2 -2
  49. package/themes/dmpatterns/desktop.css +1 -1
  50. package/themes/dmpatterns/desktop.md +1 -1
  51. package/themes/dmpatterns/desktop.scoped.css +1 -1
  52. package/themes/dmpatterns/diagram.css +1 -1
  53. package/themes/dmpatterns/diagram.md +1 -1
  54. package/themes/dmpatterns/diagram.scoped.css +1 -1
  55. package/themes/dmpatterns/mobile.css +1 -1
  56. package/themes/dmpatterns/mobile.md +1 -1
  57. package/themes/dmpatterns/mobile.scoped.css +1 -1
  58. package/themes/dmpatterns/responsive.css +2 -2
  59. package/themes/pdigest/desktop.css +1 -1
  60. package/themes/pdigest/desktop.md +1 -1
  61. package/themes/pdigest/desktop.scoped.css +1 -1
  62. package/themes/pdigest/diagram.css +1 -1
  63. package/themes/pdigest/diagram.md +1 -1
  64. package/themes/pdigest/diagram.scoped.css +1 -1
  65. package/themes/pdigest/mobile.css +1 -1
  66. package/themes/pdigest/mobile.md +1 -1
  67. package/themes/pdigest/mobile.scoped.css +1 -1
  68. package/themes/pdigest/responsive.css +2 -2
  69. package/themes/retrack/desktop.css +1 -1
  70. package/themes/retrack/desktop.md +1 -1
  71. package/themes/retrack/desktop.scoped.css +1 -1
  72. package/themes/retrack/diagram.css +1 -1
  73. package/themes/retrack/diagram.md +1 -1
  74. package/themes/retrack/diagram.scoped.css +1 -1
  75. package/themes/retrack/mobile.css +1 -1
  76. package/themes/retrack/mobile.md +1 -1
  77. package/themes/retrack/mobile.scoped.css +1 -1
  78. package/themes/retrack/responsive.css +2 -2
  79. package/tokens/themes/base/dist/desktop.json +1 -1
  80. package/tokens/themes/base/dist/diagram.json +1 -1
  81. package/tokens/themes/base/dist/mobile.json +1 -1
  82. package/tokens/themes/brandcopilot/dist/desktop.json +1 -1
  83. package/tokens/themes/brandcopilot/dist/diagram.json +1 -1
  84. package/tokens/themes/brandcopilot/dist/mobile.json +1 -1
  85. package/tokens/themes/dmpatterns/dist/desktop.json +1 -1
  86. package/tokens/themes/dmpatterns/dist/diagram.json +1 -1
  87. package/tokens/themes/dmpatterns/dist/mobile.json +1 -1
  88. package/tokens/themes/pdigest/dist/desktop.json +1 -1
  89. package/tokens/themes/pdigest/dist/diagram.json +1 -1
  90. package/tokens/themes/pdigest/dist/mobile.json +1 -1
  91. package/tokens/themes/retrack/dist/desktop.json +1 -1
  92. package/tokens/themes/retrack/dist/diagram.json +1 -1
  93. package/tokens/themes/retrack/dist/mobile.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/dropdown/dropdown.tsx"],"names":["useRef","useState","classnames","cloneElement","useEffect","jsxs","jsx"],"mappings":"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","file":"dropdown.cjs","sourcesContent":["import React, {\n cloneElement,\n useEffect,\n useRef,\n useState,\n} from 'react';\n\nimport './dropdown.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface DropdownOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport type DropdownInteraction =\n | 'click'\n | 'hover';\n\ntype DropdownTriggerProps = {\n className?: string;\n onClick?: (\n event: React.MouseEvent,\n ) => void;\n 'aria-haspopup'?: string;\n 'aria-expanded'?: boolean;\n};\n\ntype DropdownTriggerElement =\n React.ReactElement<DropdownTriggerProps>;\n\nexport interface DropdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange'\n > {\n options: DropdownOption[];\n value?: string;\n defaultValue?: string;\n label?: string;\n align?:\n | 'top-start'\n | 'top-end'\n | 'bottom-start'\n | 'bottom-end';\n interaction?: DropdownInteraction;\n trigger: DropdownTriggerElement;\n onChange?: (\n value: string,\n ) => void;\n}\n\nconst Dropdown: React.FC<DropdownProps> = ({\n options,\n value,\n defaultValue,\n label = 'Dropdown',\n align = 'bottom-start',\n interaction = 'click',\n trigger,\n onChange,\n className = '',\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...props\n}) => {\n const dropdownRef =\n useRef<HTMLDivElement>(null);\n\n const [isOpen, setIsOpen] =\n useState(false);\n\n const [\n internalValue,\n setInternalValue,\n ] = useState(defaultValue);\n\n const selectedValue =\n value ?? internalValue;\n\n const isHoverInteraction =\n interaction === 'hover';\n\n const classes = classnames(\n 'dropdown',\n className,\n {\n 'dropdown--open': isOpen,\n 'dropdown--top-start':\n align === 'top-start',\n 'dropdown--top-end':\n align === 'top-end',\n 'dropdown--bottom-start':\n align === 'bottom-start',\n 'dropdown--bottom-end':\n align === 'bottom-end',\n },\n );\n\n const triggerElement =\n trigger as DropdownTriggerElement;\n\n const triggerClasses = classnames(\n 'dropdown__trigger',\n triggerElement.props.className,\n );\n\n const resolvedTrigger = cloneElement(\n triggerElement,\n {\n className: triggerClasses,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n\n onClick: (\n event: React.MouseEvent,\n ) => {\n triggerElement.props.onClick?.(\n event,\n );\n\n if (isHoverInteraction) {\n return;\n }\n\n setIsOpen(\n (currentValue) =>\n !currentValue,\n );\n },\n },\n );\n\n const handleOptionClick = (\n option: DropdownOption,\n ) => {\n if (option.disabled) {\n return;\n }\n\n if (value === undefined) {\n setInternalValue(option.value);\n }\n\n onChange?.(option.value);\n setIsOpen(false);\n };\n\n const handleMouseEnter = (\n event: React.MouseEvent<HTMLDivElement>,\n ) => {\n onMouseEnter?.(event);\n\n if (isHoverInteraction) {\n setIsOpen(true);\n }\n };\n\n const handleMouseLeave = (\n event: React.MouseEvent<HTMLDivElement>,\n ) => {\n onMouseLeave?.(event);\n\n if (isHoverInteraction) {\n setIsOpen(false);\n }\n };\n\n const handleFocus = (\n event: React.FocusEvent<HTMLDivElement>,\n ) => {\n onFocus?.(event);\n\n if (isHoverInteraction) {\n setIsOpen(true);\n }\n };\n\n const handleBlur = (\n event: React.FocusEvent<HTMLDivElement>,\n ) => {\n onBlur?.(event);\n\n if (!isHoverInteraction) {\n return;\n }\n\n const nextTarget =\n event.relatedTarget;\n\n if (\n nextTarget instanceof Node &&\n event.currentTarget.contains(\n nextTarget,\n )\n ) {\n return;\n }\n\n setIsOpen(false);\n };\n\n useEffect(() => {\n if (!isOpen) {\n return;\n }\n\n const handleDocumentClick = (\n event: MouseEvent,\n ) => {\n const dropdown =\n dropdownRef.current;\n\n if (\n !dropdown ||\n dropdown.contains(\n event.target as Node,\n )\n ) {\n return;\n }\n\n setIsOpen(false);\n };\n\n const handleDocumentKeyDown = (\n event: KeyboardEvent,\n ) => {\n if (event.key === 'Escape') {\n setIsOpen(false);\n }\n };\n\n document.addEventListener(\n 'mousedown',\n handleDocumentClick,\n );\n\n document.addEventListener(\n 'keydown',\n handleDocumentKeyDown,\n );\n\n return () => {\n document.removeEventListener(\n 'mousedown',\n handleDocumentClick,\n );\n\n document.removeEventListener(\n 'keydown',\n handleDocumentKeyDown,\n );\n };\n }, [isOpen]);\n\n return (\n <div\n ref={dropdownRef}\n className={classes}\n onMouseEnter={\n handleMouseEnter\n }\n onMouseLeave={\n handleMouseLeave\n }\n onFocus={handleFocus}\n onBlur={handleBlur}\n {...props}\n >\n {resolvedTrigger}\n\n {isOpen && (\n <div\n className=\"dropdown__menu\"\n role=\"menu\"\n aria-label={label}\n >\n {options.map((option) => {\n const isSelected =\n option.value ===\n selectedValue;\n\n const itemClasses =\n classnames(\n 'dropdown__item',\n {\n 'dropdown__item--selected':\n isSelected,\n 'dropdown__item--disabled':\n option.disabled,\n },\n );\n\n return (\n <button\n key={option.value}\n className={\n itemClasses\n }\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={\n isSelected\n }\n aria-disabled={\n option.disabled\n }\n disabled={\n option.disabled\n }\n onClick={() =>\n handleOptionClick(\n option,\n )\n }\n >\n {option.label}\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n\nexport default Dropdown;\n"]}
1
+ {"version":3,"sources":["../../../src/components/dropdown/dropdown.tsx"],"names":["useRef","useState","classnames","cloneElement","useEffect","jsxs","jsx"],"mappings":"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","file":"dropdown.cjs","sourcesContent":["import React, {\n cloneElement,\n useEffect,\n useRef,\n useState,\n} from 'react';\n\nimport './dropdown.css';\nimport { classnames } from '../helpers/classnames';\n\nconst HOVER_CLOSE_DELAY_MS = 150;\n\nexport interface DropdownOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport type DropdownInteraction =\n | 'click'\n | 'hover';\n\ntype DropdownTriggerProps = {\n className?: string;\n onClick?: (\n event: React.MouseEvent,\n ) => void;\n 'aria-haspopup'?: string;\n 'aria-expanded'?: boolean;\n};\n\ntype DropdownTriggerElement =\n React.ReactElement<DropdownTriggerProps>;\n\nexport interface DropdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange'\n > {\n options: DropdownOption[];\n value?: string;\n defaultValue?: string;\n label?: string;\n align?:\n | 'top-start'\n | 'top-end'\n | 'bottom-start'\n | 'bottom-end';\n interaction?: DropdownInteraction;\n trigger: DropdownTriggerElement;\n onChange?: (\n value: string,\n ) => void;\n}\n\nconst Dropdown: React.FC<DropdownProps> = ({\n options,\n value,\n defaultValue,\n label = 'Dropdown',\n align = 'bottom-start',\n interaction = 'click',\n trigger,\n onChange,\n className = '',\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...props\n}) => {\n const dropdownRef =\n useRef<HTMLDivElement>(null);\n\n const hoverCloseTimeoutRef =\n useRef<ReturnType<\n typeof setTimeout\n > | null>(null);\n\n const [isOpen, setIsOpen] =\n useState(false);\n\n const [\n internalValue,\n setInternalValue,\n ] = useState(defaultValue);\n\n const selectedValue =\n value ?? internalValue;\n\n const isHoverInteraction =\n interaction === 'hover';\n\n const clearHoverCloseTimeout =\n () => {\n if (\n hoverCloseTimeoutRef.current ===\n null\n ) {\n return;\n }\n\n clearTimeout(\n hoverCloseTimeoutRef.current,\n );\n\n hoverCloseTimeoutRef.current =\n null;\n };\n\n const closeDropdown = () => {\n clearHoverCloseTimeout();\n setIsOpen(false);\n };\n\n const scheduleHoverClose = () => {\n clearHoverCloseTimeout();\n\n hoverCloseTimeoutRef.current =\n setTimeout(() => {\n hoverCloseTimeoutRef.current =\n null;\n setIsOpen(false);\n }, HOVER_CLOSE_DELAY_MS);\n };\n\n const classes = classnames(\n 'dropdown',\n className,\n {\n 'dropdown--open': isOpen,\n 'dropdown--top-start':\n align === 'top-start',\n 'dropdown--top-end':\n align === 'top-end',\n 'dropdown--bottom-start':\n align === 'bottom-start',\n 'dropdown--bottom-end':\n align === 'bottom-end',\n },\n );\n\n const triggerElement =\n trigger as DropdownTriggerElement;\n\n const triggerClasses = classnames(\n 'dropdown__trigger',\n triggerElement.props.className,\n );\n\n const resolvedTrigger = cloneElement(\n triggerElement,\n {\n className: triggerClasses,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n\n onClick: (\n event: React.MouseEvent,\n ) => {\n triggerElement.props.onClick?.(\n event,\n );\n\n if (isHoverInteraction) {\n return;\n }\n\n setIsOpen(\n (currentValue) =>\n !currentValue,\n );\n },\n },\n );\n\n const handleOptionClick = (\n option: DropdownOption,\n ) => {\n if (option.disabled) {\n return;\n }\n\n if (value === undefined) {\n setInternalValue(option.value);\n }\n\n onChange?.(option.value);\n closeDropdown();\n };\n\n const handleMouseEnter = (\n event: React.MouseEvent<HTMLDivElement>,\n ) => {\n onMouseEnter?.(event);\n\n if (isHoverInteraction) {\n clearHoverCloseTimeout();\n setIsOpen(true);\n }\n };\n\n const handleMouseLeave = (\n event: React.MouseEvent<HTMLDivElement>,\n ) => {\n onMouseLeave?.(event);\n\n if (isHoverInteraction) {\n scheduleHoverClose();\n }\n };\n\n const handleFocus = (\n event: React.FocusEvent<HTMLDivElement>,\n ) => {\n onFocus?.(event);\n\n if (isHoverInteraction) {\n clearHoverCloseTimeout();\n setIsOpen(true);\n }\n };\n\n const handleBlur = (\n event: React.FocusEvent<HTMLDivElement>,\n ) => {\n onBlur?.(event);\n\n if (!isHoverInteraction) {\n return;\n }\n\n const nextTarget =\n event.relatedTarget;\n\n if (\n nextTarget instanceof Node &&\n event.currentTarget.contains(\n nextTarget,\n )\n ) {\n return;\n }\n\n closeDropdown();\n };\n\n useEffect(() => {\n return () => {\n clearHoverCloseTimeout();\n };\n }, []);\n\n useEffect(() => {\n if (!isOpen) {\n return;\n }\n\n const handleDocumentClick = (\n event: MouseEvent,\n ) => {\n const dropdown =\n dropdownRef.current;\n\n if (\n !dropdown ||\n dropdown.contains(\n event.target as Node,\n )\n ) {\n return;\n }\n\n closeDropdown();\n };\n\n const handleDocumentKeyDown = (\n event: KeyboardEvent,\n ) => {\n if (event.key === 'Escape') {\n closeDropdown();\n }\n };\n\n document.addEventListener(\n 'mousedown',\n handleDocumentClick,\n );\n\n document.addEventListener(\n 'keydown',\n handleDocumentKeyDown,\n );\n\n return () => {\n document.removeEventListener(\n 'mousedown',\n handleDocumentClick,\n );\n\n document.removeEventListener(\n 'keydown',\n handleDocumentKeyDown,\n );\n };\n }, [isOpen]);\n\n return (\n <div\n ref={dropdownRef}\n className={classes}\n onMouseEnter={\n handleMouseEnter\n }\n onMouseLeave={\n handleMouseLeave\n }\n onFocus={handleFocus}\n onBlur={handleBlur}\n {...props}\n >\n {resolvedTrigger}\n\n {isOpen && (\n <div\n className=\"dropdown__menu\"\n role=\"menu\"\n aria-label={label}\n >\n {options.map((option) => {\n const isSelected =\n option.value ===\n selectedValue;\n\n const itemClasses =\n classnames(\n 'dropdown__item',\n {\n 'dropdown__item--selected':\n isSelected,\n 'dropdown__item--disabled':\n option.disabled,\n },\n );\n\n return (\n <button\n key={option.value}\n className={\n itemClasses\n }\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={\n isSelected\n }\n aria-disabled={\n option.disabled\n }\n disabled={\n option.disabled\n }\n onClick={() =>\n handleOptionClick(\n option,\n )\n }\n >\n {option.label}\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n\nexport default Dropdown;\n"]}
@@ -3,6 +3,7 @@ import { useRef, useState, cloneElement, useEffect } from 'react';
3
3
  import './dropdown.css';
4
4
  import { classnames } from '../helpers/classnames';
5
5
 
6
+ const HOVER_CLOSE_DELAY_MS = 150;
6
7
  const Dropdown = ({
7
8
  options,
8
9
  value,
@@ -20,6 +21,7 @@ const Dropdown = ({
20
21
  ...props
21
22
  }) => {
22
23
  const dropdownRef = useRef(null);
24
+ const hoverCloseTimeoutRef = useRef(null);
23
25
  const [isOpen, setIsOpen] = useState(false);
24
26
  const [
25
27
  internalValue,
@@ -27,6 +29,26 @@ const Dropdown = ({
27
29
  ] = useState(defaultValue);
28
30
  const selectedValue = value ?? internalValue;
29
31
  const isHoverInteraction = interaction === "hover";
32
+ const clearHoverCloseTimeout = () => {
33
+ if (hoverCloseTimeoutRef.current === null) {
34
+ return;
35
+ }
36
+ clearTimeout(
37
+ hoverCloseTimeoutRef.current
38
+ );
39
+ hoverCloseTimeoutRef.current = null;
40
+ };
41
+ const closeDropdown = () => {
42
+ clearHoverCloseTimeout();
43
+ setIsOpen(false);
44
+ };
45
+ const scheduleHoverClose = () => {
46
+ clearHoverCloseTimeout();
47
+ hoverCloseTimeoutRef.current = setTimeout(() => {
48
+ hoverCloseTimeoutRef.current = null;
49
+ setIsOpen(false);
50
+ }, HOVER_CLOSE_DELAY_MS);
51
+ };
30
52
  const classes = classnames(
31
53
  "dropdown",
32
54
  className,
@@ -70,23 +92,25 @@ const Dropdown = ({
70
92
  setInternalValue(option.value);
71
93
  }
72
94
  onChange?.(option.value);
73
- setIsOpen(false);
95
+ closeDropdown();
74
96
  };
75
97
  const handleMouseEnter = (event) => {
76
98
  onMouseEnter?.(event);
77
99
  if (isHoverInteraction) {
100
+ clearHoverCloseTimeout();
78
101
  setIsOpen(true);
79
102
  }
80
103
  };
81
104
  const handleMouseLeave = (event) => {
82
105
  onMouseLeave?.(event);
83
106
  if (isHoverInteraction) {
84
- setIsOpen(false);
107
+ scheduleHoverClose();
85
108
  }
86
109
  };
87
110
  const handleFocus = (event) => {
88
111
  onFocus?.(event);
89
112
  if (isHoverInteraction) {
113
+ clearHoverCloseTimeout();
90
114
  setIsOpen(true);
91
115
  }
92
116
  };
@@ -101,8 +125,13 @@ const Dropdown = ({
101
125
  )) {
102
126
  return;
103
127
  }
104
- setIsOpen(false);
128
+ closeDropdown();
105
129
  };
130
+ useEffect(() => {
131
+ return () => {
132
+ clearHoverCloseTimeout();
133
+ };
134
+ }, []);
106
135
  useEffect(() => {
107
136
  if (!isOpen) {
108
137
  return;
@@ -114,11 +143,11 @@ const Dropdown = ({
114
143
  )) {
115
144
  return;
116
145
  }
117
- setIsOpen(false);
146
+ closeDropdown();
118
147
  };
119
148
  const handleDocumentKeyDown = (event) => {
120
149
  if (event.key === "Escape") {
121
- setIsOpen(false);
150
+ closeDropdown();
122
151
  }
123
152
  };
124
153
  document.addEventListener(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/dropdown/dropdown.tsx"],"names":[],"mappings":"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","file":"dropdown.js","sourcesContent":["import React, {\n cloneElement,\n useEffect,\n useRef,\n useState,\n} from 'react';\n\nimport './dropdown.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface DropdownOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport type DropdownInteraction =\n | 'click'\n | 'hover';\n\ntype DropdownTriggerProps = {\n className?: string;\n onClick?: (\n event: React.MouseEvent,\n ) => void;\n 'aria-haspopup'?: string;\n 'aria-expanded'?: boolean;\n};\n\ntype DropdownTriggerElement =\n React.ReactElement<DropdownTriggerProps>;\n\nexport interface DropdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange'\n > {\n options: DropdownOption[];\n value?: string;\n defaultValue?: string;\n label?: string;\n align?:\n | 'top-start'\n | 'top-end'\n | 'bottom-start'\n | 'bottom-end';\n interaction?: DropdownInteraction;\n trigger: DropdownTriggerElement;\n onChange?: (\n value: string,\n ) => void;\n}\n\nconst Dropdown: React.FC<DropdownProps> = ({\n options,\n value,\n defaultValue,\n label = 'Dropdown',\n align = 'bottom-start',\n interaction = 'click',\n trigger,\n onChange,\n className = '',\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...props\n}) => {\n const dropdownRef =\n useRef<HTMLDivElement>(null);\n\n const [isOpen, setIsOpen] =\n useState(false);\n\n const [\n internalValue,\n setInternalValue,\n ] = useState(defaultValue);\n\n const selectedValue =\n value ?? internalValue;\n\n const isHoverInteraction =\n interaction === 'hover';\n\n const classes = classnames(\n 'dropdown',\n className,\n {\n 'dropdown--open': isOpen,\n 'dropdown--top-start':\n align === 'top-start',\n 'dropdown--top-end':\n align === 'top-end',\n 'dropdown--bottom-start':\n align === 'bottom-start',\n 'dropdown--bottom-end':\n align === 'bottom-end',\n },\n );\n\n const triggerElement =\n trigger as DropdownTriggerElement;\n\n const triggerClasses = classnames(\n 'dropdown__trigger',\n triggerElement.props.className,\n );\n\n const resolvedTrigger = cloneElement(\n triggerElement,\n {\n className: triggerClasses,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n\n onClick: (\n event: React.MouseEvent,\n ) => {\n triggerElement.props.onClick?.(\n event,\n );\n\n if (isHoverInteraction) {\n return;\n }\n\n setIsOpen(\n (currentValue) =>\n !currentValue,\n );\n },\n },\n );\n\n const handleOptionClick = (\n option: DropdownOption,\n ) => {\n if (option.disabled) {\n return;\n }\n\n if (value === undefined) {\n setInternalValue(option.value);\n }\n\n onChange?.(option.value);\n setIsOpen(false);\n };\n\n const handleMouseEnter = (\n event: React.MouseEvent<HTMLDivElement>,\n ) => {\n onMouseEnter?.(event);\n\n if (isHoverInteraction) {\n setIsOpen(true);\n }\n };\n\n const handleMouseLeave = (\n event: React.MouseEvent<HTMLDivElement>,\n ) => {\n onMouseLeave?.(event);\n\n if (isHoverInteraction) {\n setIsOpen(false);\n }\n };\n\n const handleFocus = (\n event: React.FocusEvent<HTMLDivElement>,\n ) => {\n onFocus?.(event);\n\n if (isHoverInteraction) {\n setIsOpen(true);\n }\n };\n\n const handleBlur = (\n event: React.FocusEvent<HTMLDivElement>,\n ) => {\n onBlur?.(event);\n\n if (!isHoverInteraction) {\n return;\n }\n\n const nextTarget =\n event.relatedTarget;\n\n if (\n nextTarget instanceof Node &&\n event.currentTarget.contains(\n nextTarget,\n )\n ) {\n return;\n }\n\n setIsOpen(false);\n };\n\n useEffect(() => {\n if (!isOpen) {\n return;\n }\n\n const handleDocumentClick = (\n event: MouseEvent,\n ) => {\n const dropdown =\n dropdownRef.current;\n\n if (\n !dropdown ||\n dropdown.contains(\n event.target as Node,\n )\n ) {\n return;\n }\n\n setIsOpen(false);\n };\n\n const handleDocumentKeyDown = (\n event: KeyboardEvent,\n ) => {\n if (event.key === 'Escape') {\n setIsOpen(false);\n }\n };\n\n document.addEventListener(\n 'mousedown',\n handleDocumentClick,\n );\n\n document.addEventListener(\n 'keydown',\n handleDocumentKeyDown,\n );\n\n return () => {\n document.removeEventListener(\n 'mousedown',\n handleDocumentClick,\n );\n\n document.removeEventListener(\n 'keydown',\n handleDocumentKeyDown,\n );\n };\n }, [isOpen]);\n\n return (\n <div\n ref={dropdownRef}\n className={classes}\n onMouseEnter={\n handleMouseEnter\n }\n onMouseLeave={\n handleMouseLeave\n }\n onFocus={handleFocus}\n onBlur={handleBlur}\n {...props}\n >\n {resolvedTrigger}\n\n {isOpen && (\n <div\n className=\"dropdown__menu\"\n role=\"menu\"\n aria-label={label}\n >\n {options.map((option) => {\n const isSelected =\n option.value ===\n selectedValue;\n\n const itemClasses =\n classnames(\n 'dropdown__item',\n {\n 'dropdown__item--selected':\n isSelected,\n 'dropdown__item--disabled':\n option.disabled,\n },\n );\n\n return (\n <button\n key={option.value}\n className={\n itemClasses\n }\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={\n isSelected\n }\n aria-disabled={\n option.disabled\n }\n disabled={\n option.disabled\n }\n onClick={() =>\n handleOptionClick(\n option,\n )\n }\n >\n {option.label}\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n\nexport default Dropdown;\n"]}
1
+ {"version":3,"sources":["../../../src/components/dropdown/dropdown.tsx"],"names":[],"mappings":";;;;;AAUA,MAAM,oBAAA,GAAuB,GAAA;AA6C7B,MAAM,WAAoC,CAAC;AAAA,EACzC,OAAA;AAAA,EACA,KAAA;AAAA,EACA,YAAA;AAAA,EACA,KAAA,GAAQ,UAAA;AAAA,EACR,KAAA,GAAQ,cAAA;AAAA,EACR,WAAA,GAAc,OAAA;AAAA,EACd,OAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ,YAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,GAAG;AACL,CAAA,KAAM;AACJ,EAAA,MAAM,WAAA,GACJ,OAAuB,IAAI,CAAA;AAE7B,EAAA,MAAM,oBAAA,GACJ,OAEU,IAAI,CAAA;AAEhB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GACtB,SAAS,KAAK,CAAA;AAEhB,EAAA,MAAM;AAAA,IACJ,aAAA;AAAA,IACA;AAAA,GACF,GAAI,SAAS,YAAY,CAAA;AAEzB,EAAA,MAAM,gBACJ,KAAA,IAAS,aAAA;AAEX,EAAA,MAAM,qBACJ,WAAA,KAAgB,OAAA;AAElB,EAAA,MAAM,yBACJ,MAAM;AACJ,IAAA,IACE,oBAAA,CAAqB,YACrB,IAAA,EACA;AACA,MAAA;AAAA,IACF;AAEA,IAAA,YAAA;AAAA,MACE,oBAAA,CAAqB;AAAA,KACvB;AAEA,IAAA,oBAAA,CAAqB,OAAA,GACnB,IAAA;AAAA,EACJ,CAAA;AAEF,EAAA,MAAM,gBAAgB,MAAM;AAC1B,IAAA,sBAAA,EAAuB;AACvB,IAAA,SAAA,CAAU,KAAK,CAAA;AAAA,EACjB,CAAA;AAEA,EAAA,MAAM,qBAAqB,MAAM;AAC/B,IAAA,sBAAA,EAAuB;AAEvB,IAAA,oBAAA,CAAqB,OAAA,GACnB,WAAW,MAAM;AACf,MAAA,oBAAA,CAAqB,OAAA,GACnB,IAAA;AACF,MAAA,SAAA,CAAU,KAAK,CAAA;AAAA,IACjB,GAAG,oBAAoB,CAAA;AAAA,EAC3B,CAAA;AAEA,EAAA,MAAM,OAAA,GAAU,UAAA;AAAA,IACd,UAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,MACE,gBAAA,EAAkB,MAAA;AAAA,MAClB,uBACE,KAAA,KAAU,WAAA;AAAA,MACZ,qBACE,KAAA,KAAU,SAAA;AAAA,MACZ,0BACE,KAAA,KAAU,cAAA;AAAA,MACZ,wBACE,KAAA,KAAU;AAAA;AACd,GACF;AAEA,EAAA,MAAM,cAAA,GACJ,OAAA;AAEF,EAAA,MAAM,cAAA,GAAiB,UAAA;AAAA,IACrB,mBAAA;AAAA,IACA,eAAe,KAAA,CAAM;AAAA,GACvB;AAEA,EAAA,MAAM,eAAA,GAAkB,YAAA;AAAA,IACtB,cAAA;AAAA,IACA;AAAA,MACE,SAAA,EAAW,cAAA;AAAA,MACX,eAAA,EAAiB,MAAA;AAAA,MACjB,eAAA,EAAiB,MAAA;AAAA,MAEjB,OAAA,EAAS,CACP,KAAA,KACG;AACH,QAAA,cAAA,CAAe,KAAA,CAAM,OAAA;AAAA,UACnB;AAAA,SACF;AAEA,QAAA,IAAI,kBAAA,EAAoB;AACtB,UAAA;AAAA,QACF;AAEA,QAAA,SAAA;AAAA,UACE,CAAC,iBACC,CAAC;AAAA,SACL;AAAA,MACF;AAAA;AACF,GACF;AAEA,EAAA,MAAM,iBAAA,GAAoB,CACxB,MAAA,KACG;AACH,IAAA,IAAI,OAAO,QAAA,EAAU;AACnB,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,UAAU,MAAA,EAAW;AACvB,MAAA,gBAAA,CAAiB,OAAO,KAAK,CAAA;AAAA,IAC/B;AAEA,IAAA,QAAA,GAAW,OAAO,KAAK,CAAA;AACvB,IAAA,aAAA,EAAc;AAAA,EAChB,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,CACvB,KAAA,KACG;AACH,IAAA,YAAA,GAAe,KAAK,CAAA;AAEpB,IAAA,IAAI,kBAAA,EAAoB;AACtB,MAAA,sBAAA,EAAuB;AACvB,MAAA,SAAA,CAAU,IAAI,CAAA;AAAA,IAChB;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,CACvB,KAAA,KACG;AACH,IAAA,YAAA,GAAe,KAAK,CAAA;AAEpB,IAAA,IAAI,kBAAA,EAAoB;AACtB,MAAA,kBAAA,EAAmB;AAAA,IACrB;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAClB,KAAA,KACG;AACH,IAAA,OAAA,GAAU,KAAK,CAAA;AAEf,IAAA,IAAI,kBAAA,EAAoB;AACtB,MAAA,sBAAA,EAAuB;AACvB,MAAA,SAAA,CAAU,IAAI,CAAA;AAAA,IAChB;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,UAAA,GAAa,CACjB,KAAA,KACG;AACH,IAAA,MAAA,GAAS,KAAK,CAAA;AAEd,IAAA,IAAI,CAAC,kBAAA,EAAoB;AACvB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,aACJ,KAAA,CAAM,aAAA;AAER,IAAA,IACE,UAAA,YAAsB,IAAA,IACtB,KAAA,CAAM,aAAA,CAAc,QAAA;AAAA,MAClB;AAAA,KACF,EACA;AACA,MAAA;AAAA,IACF;AAEA,IAAA,aAAA,EAAc;AAAA,EAChB,CAAA;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,OAAO,MAAM;AACX,MAAA,sBAAA,EAAuB;AAAA,IACzB,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,mBAAA,GAAsB,CAC1B,KAAA,KACG;AACH,MAAA,MAAM,WACJ,WAAA,CAAY,OAAA;AAEd,MAAA,IACE,CAAC,YACD,QAAA,CAAS,QAAA;AAAA,QACP,KAAA,CAAM;AAAA,OACR,EACA;AACA,QAAA;AAAA,MACF;AAEA,MAAA,aAAA,EAAc;AAAA,IAChB,CAAA;AAEA,IAAA,MAAM,qBAAA,GAAwB,CAC5B,KAAA,KACG;AACH,MAAA,IAAI,KAAA,CAAM,QAAQ,QAAA,EAAU;AAC1B,QAAA,aAAA,EAAc;AAAA,MAChB;AAAA,IACF,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA;AAAA,MACP,WAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,QAAA,CAAS,gBAAA;AAAA,MACP,SAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA;AAAA,QACP,WAAA;AAAA,QACA;AAAA,OACF;AAEA,MAAA,QAAA,CAAS,mBAAA;AAAA,QACP,SAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,WAAA;AAAA,MACL,SAAA,EAAW,OAAA;AAAA,MACX,YAAA,EACE,gBAAA;AAAA,MAEF,YAAA,EACE,gBAAA;AAAA,MAEF,OAAA,EAAS,WAAA;AAAA,MACT,MAAA,EAAQ,UAAA;AAAA,MACP,GAAG,KAAA;AAAA,MAEH,QAAA,EAAA;AAAA,QAAA,eAAA;AAAA,QAEA,MAAA,oBACC,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAU,gBAAA;AAAA,YACV,IAAA,EAAK,MAAA;AAAA,YACL,YAAA,EAAY,KAAA;AAAA,YAEX,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAW;AACvB,cAAA,MAAM,UAAA,GACJ,OAAO,KAAA,KACP,aAAA;AAEF,cAAA,MAAM,WAAA,GACJ,UAAA;AAAA,gBACE,gBAAA;AAAA,gBACA;AAAA,kBACE,0BAAA,EACE,UAAA;AAAA,kBACF,4BACE,MAAA,CAAO;AAAA;AACX,eACF;AAEF,cAAA,uBACE,GAAA;AAAA,gBAAC,QAAA;AAAA,gBAAA;AAAA,kBAEC,SAAA,EACE,WAAA;AAAA,kBAEF,IAAA,EAAK,QAAA;AAAA,kBACL,IAAA,EAAK,eAAA;AAAA,kBACL,cAAA,EACE,UAAA;AAAA,kBAEF,iBACE,MAAA,CAAO,QAAA;AAAA,kBAET,UACE,MAAA,CAAO,QAAA;AAAA,kBAET,SAAS,MACP,iBAAA;AAAA,oBACE;AAAA,mBACF;AAAA,kBAGD,QAAA,EAAA,MAAA,CAAO;AAAA,iBAAA;AAAA,gBArBH,MAAA,CAAO;AAAA,eAsBd;AAAA,YAEJ,CAAC;AAAA;AAAA;AACH;AAAA;AAAA,GAEJ;AAEJ,CAAA;AAEA,IAAO,gBAAA,GAAQ","file":"dropdown.js","sourcesContent":["import React, {\n cloneElement,\n useEffect,\n useRef,\n useState,\n} from 'react';\n\nimport './dropdown.css';\nimport { classnames } from '../helpers/classnames';\n\nconst HOVER_CLOSE_DELAY_MS = 150;\n\nexport interface DropdownOption {\n value: string;\n label: string;\n disabled?: boolean;\n}\n\nexport type DropdownInteraction =\n | 'click'\n | 'hover';\n\ntype DropdownTriggerProps = {\n className?: string;\n onClick?: (\n event: React.MouseEvent,\n ) => void;\n 'aria-haspopup'?: string;\n 'aria-expanded'?: boolean;\n};\n\ntype DropdownTriggerElement =\n React.ReactElement<DropdownTriggerProps>;\n\nexport interface DropdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange'\n > {\n options: DropdownOption[];\n value?: string;\n defaultValue?: string;\n label?: string;\n align?:\n | 'top-start'\n | 'top-end'\n | 'bottom-start'\n | 'bottom-end';\n interaction?: DropdownInteraction;\n trigger: DropdownTriggerElement;\n onChange?: (\n value: string,\n ) => void;\n}\n\nconst Dropdown: React.FC<DropdownProps> = ({\n options,\n value,\n defaultValue,\n label = 'Dropdown',\n align = 'bottom-start',\n interaction = 'click',\n trigger,\n onChange,\n className = '',\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...props\n}) => {\n const dropdownRef =\n useRef<HTMLDivElement>(null);\n\n const hoverCloseTimeoutRef =\n useRef<ReturnType<\n typeof setTimeout\n > | null>(null);\n\n const [isOpen, setIsOpen] =\n useState(false);\n\n const [\n internalValue,\n setInternalValue,\n ] = useState(defaultValue);\n\n const selectedValue =\n value ?? internalValue;\n\n const isHoverInteraction =\n interaction === 'hover';\n\n const clearHoverCloseTimeout =\n () => {\n if (\n hoverCloseTimeoutRef.current ===\n null\n ) {\n return;\n }\n\n clearTimeout(\n hoverCloseTimeoutRef.current,\n );\n\n hoverCloseTimeoutRef.current =\n null;\n };\n\n const closeDropdown = () => {\n clearHoverCloseTimeout();\n setIsOpen(false);\n };\n\n const scheduleHoverClose = () => {\n clearHoverCloseTimeout();\n\n hoverCloseTimeoutRef.current =\n setTimeout(() => {\n hoverCloseTimeoutRef.current =\n null;\n setIsOpen(false);\n }, HOVER_CLOSE_DELAY_MS);\n };\n\n const classes = classnames(\n 'dropdown',\n className,\n {\n 'dropdown--open': isOpen,\n 'dropdown--top-start':\n align === 'top-start',\n 'dropdown--top-end':\n align === 'top-end',\n 'dropdown--bottom-start':\n align === 'bottom-start',\n 'dropdown--bottom-end':\n align === 'bottom-end',\n },\n );\n\n const triggerElement =\n trigger as DropdownTriggerElement;\n\n const triggerClasses = classnames(\n 'dropdown__trigger',\n triggerElement.props.className,\n );\n\n const resolvedTrigger = cloneElement(\n triggerElement,\n {\n className: triggerClasses,\n 'aria-haspopup': 'menu',\n 'aria-expanded': isOpen,\n\n onClick: (\n event: React.MouseEvent,\n ) => {\n triggerElement.props.onClick?.(\n event,\n );\n\n if (isHoverInteraction) {\n return;\n }\n\n setIsOpen(\n (currentValue) =>\n !currentValue,\n );\n },\n },\n );\n\n const handleOptionClick = (\n option: DropdownOption,\n ) => {\n if (option.disabled) {\n return;\n }\n\n if (value === undefined) {\n setInternalValue(option.value);\n }\n\n onChange?.(option.value);\n closeDropdown();\n };\n\n const handleMouseEnter = (\n event: React.MouseEvent<HTMLDivElement>,\n ) => {\n onMouseEnter?.(event);\n\n if (isHoverInteraction) {\n clearHoverCloseTimeout();\n setIsOpen(true);\n }\n };\n\n const handleMouseLeave = (\n event: React.MouseEvent<HTMLDivElement>,\n ) => {\n onMouseLeave?.(event);\n\n if (isHoverInteraction) {\n scheduleHoverClose();\n }\n };\n\n const handleFocus = (\n event: React.FocusEvent<HTMLDivElement>,\n ) => {\n onFocus?.(event);\n\n if (isHoverInteraction) {\n clearHoverCloseTimeout();\n setIsOpen(true);\n }\n };\n\n const handleBlur = (\n event: React.FocusEvent<HTMLDivElement>,\n ) => {\n onBlur?.(event);\n\n if (!isHoverInteraction) {\n return;\n }\n\n const nextTarget =\n event.relatedTarget;\n\n if (\n nextTarget instanceof Node &&\n event.currentTarget.contains(\n nextTarget,\n )\n ) {\n return;\n }\n\n closeDropdown();\n };\n\n useEffect(() => {\n return () => {\n clearHoverCloseTimeout();\n };\n }, []);\n\n useEffect(() => {\n if (!isOpen) {\n return;\n }\n\n const handleDocumentClick = (\n event: MouseEvent,\n ) => {\n const dropdown =\n dropdownRef.current;\n\n if (\n !dropdown ||\n dropdown.contains(\n event.target as Node,\n )\n ) {\n return;\n }\n\n closeDropdown();\n };\n\n const handleDocumentKeyDown = (\n event: KeyboardEvent,\n ) => {\n if (event.key === 'Escape') {\n closeDropdown();\n }\n };\n\n document.addEventListener(\n 'mousedown',\n handleDocumentClick,\n );\n\n document.addEventListener(\n 'keydown',\n handleDocumentKeyDown,\n );\n\n return () => {\n document.removeEventListener(\n 'mousedown',\n handleDocumentClick,\n );\n\n document.removeEventListener(\n 'keydown',\n handleDocumentKeyDown,\n );\n };\n }, [isOpen]);\n\n return (\n <div\n ref={dropdownRef}\n className={classes}\n onMouseEnter={\n handleMouseEnter\n }\n onMouseLeave={\n handleMouseLeave\n }\n onFocus={handleFocus}\n onBlur={handleBlur}\n {...props}\n >\n {resolvedTrigger}\n\n {isOpen && (\n <div\n className=\"dropdown__menu\"\n role=\"menu\"\n aria-label={label}\n >\n {options.map((option) => {\n const isSelected =\n option.value ===\n selectedValue;\n\n const itemClasses =\n classnames(\n 'dropdown__item',\n {\n 'dropdown__item--selected':\n isSelected,\n 'dropdown__item--disabled':\n option.disabled,\n },\n );\n\n return (\n <button\n key={option.value}\n className={\n itemClasses\n }\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={\n isSelected\n }\n aria-disabled={\n option.disabled\n }\n disabled={\n option.disabled\n }\n onClick={() =>\n handleOptionClick(\n option,\n )\n }\n >\n {option.label}\n </button>\n );\n })}\n </div>\n )}\n </div>\n );\n};\n\nexport default Dropdown;\n"]}
@@ -189,6 +189,10 @@ Object.defineProperty(exports, "CourseOutline", {
189
189
  enumerable: true,
190
190
  get: function () { return courseOutline__default.default; }
191
191
  });
192
+ Object.defineProperty(exports, "CourseOutlineItem", {
193
+ enumerable: true,
194
+ get: function () { return courseOutline.CourseOutlineItem; }
195
+ });
192
196
  Object.defineProperty(exports, "FlipList", {
193
197
  enumerable: true,
194
198
  get: function () { return flipList__default.default; }
@@ -50,11 +50,11 @@ export type { CardGroupProps } from './card-group/card-group';
50
50
  export { default as Breadcrumbs } from './breadcrumbs/breadcrumbs';
51
51
  export type { BreadcrumbItem, BreadcrumbsPresentation, BreadcrumbsProps, } from './breadcrumbs/breadcrumbs';
52
52
  export { default as Markdown } from './markdown/markdown';
53
- export type { MarkdownEmbed, MarkdownProps, } from './markdown/markdown';
53
+ export type { MarkdownEmbed, MarkdownLinkProps, MarkdownProps, } from './markdown/markdown';
54
54
  export { default as Discussion } from './discussion/discussion';
55
55
  export type { DiscussionItem, DiscussionProps, } from './discussion/discussion';
56
- export { default as CourseOutline } from './course-outline/course-outline';
57
- export type { CourseOutlineGroup, CourseOutlineHeadingLevel, CourseOutlineItem, CourseOutlineProps, } from './course-outline/course-outline';
56
+ export { default as CourseOutline, CourseOutlineItem, } from './course-outline/course-outline';
57
+ export type { CourseOutlineGroup, CourseOutlineHeadingLevel, CourseOutlineItemProps, CourseOutlineProps, } from './course-outline/course-outline';
58
58
  export * from './calendar-month';
59
59
  export { default as FlipList } from './flip-list/flip-list';
60
60
  export type { FlipListItem, FlipListProps, } from './flip-list/flip-list';
@@ -25,7 +25,7 @@ export { default as CardGroup } from './card-group/card-group';
25
25
  export { default as Breadcrumbs } from './breadcrumbs/breadcrumbs';
26
26
  export { default as Markdown } from './markdown/markdown';
27
27
  export { default as Discussion } from './discussion/discussion';
28
- export { default as CourseOutline } from './course-outline/course-outline';
28
+ export { default as CourseOutline, CourseOutlineItem } from './course-outline/course-outline';
29
29
  export * from './calendar-month';
30
30
  export { default as FlipList } from './flip-list/flip-list';
31
31
  export { default as AvatarUpload } from './avatar-upload/avatar-upload';
@@ -1,2 +1,2 @@
1
1
  export { default } from './markdown';
2
- export type { MarkdownEmbed, MarkdownProps, } from './markdown';
2
+ export type { MarkdownEmbed, MarkdownLinkProps, MarkdownProps, } from './markdown';
@@ -199,7 +199,7 @@ const MarkdownHeading = ({
199
199
  return /* @__PURE__ */ jsxRuntime.jsx("h6", { ...props, children });
200
200
  }
201
201
  };
202
- function createDocumentComponents(headingLevelOffset, renderEmbed) {
202
+ function createDocumentComponents(headingLevelOffset, renderEmbed, renderLink) {
203
203
  return {
204
204
  h1: ({ node: _node, ...headingProps }) => /* @__PURE__ */ jsxRuntime.jsx(
205
205
  MarkdownHeading,
@@ -249,6 +249,15 @@ function createDocumentComponents(headingLevelOffset, renderEmbed) {
249
249
  offset: headingLevelOffset
250
250
  }
251
251
  ),
252
+ a: ({
253
+ node: _node,
254
+ ...linkProps
255
+ }) => {
256
+ if (renderLink) {
257
+ return renderLink(linkProps);
258
+ }
259
+ return /* @__PURE__ */ jsxRuntime.jsx("a", { ...linkProps });
260
+ },
252
261
  div: ({
253
262
  node: _node,
254
263
  ...divProps
@@ -277,6 +286,7 @@ const Markdown = ({
277
286
  excerpt = false,
278
287
  headingLevelOffset = 0,
279
288
  renderEmbed,
289
+ renderLink,
280
290
  className = "",
281
291
  ...props
282
292
  }) => {
@@ -309,7 +319,8 @@ const Markdown = ({
309
319
  const normalizedHeadingLevelOffset = normalizeHeadingLevelOffset(headingLevelOffset);
310
320
  const documentComponents = createDocumentComponents(
311
321
  normalizedHeadingLevelOffset,
312
- renderEmbed
322
+ renderEmbed,
323
+ renderLink
313
324
  );
314
325
  return /* @__PURE__ */ jsxRuntime.jsx(
315
326
  "div",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/markdown/markdown.tsx"],"names":["jsx","classnames","ReactMarkdown","remarkGfm","remarkDirective"],"mappings":"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","file":"markdown.cjs","sourcesContent":["import React from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport remarkDirective from 'remark-directive';\nimport remarkGfm from 'remark-gfm';\nimport type { Plugin } from 'unified';\n\nimport './markdown.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface MarkdownEmbed {\n src: string;\n label: string;\n}\n\nexport interface MarkdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children' | 'dangerouslySetInnerHTML'\n > {\n content: string;\n excerpt?: boolean;\n headingLevelOffset?: number;\n renderEmbed?: (\n embed: MarkdownEmbed,\n ) => React.ReactNode;\n}\n\ninterface MarkdownHeadingProps\n extends React.HTMLAttributes<HTMLHeadingElement> {\n sourceLevel: number;\n offset: number;\n}\n\ntype MarkdownNodeData = {\n hName?: string;\n hProperties?: Record<string, unknown>;\n hChildren?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownNode = {\n type: string;\n name?: string;\n value?: string;\n alt?: string | null;\n attributes?: Record<\n string,\n string | null | undefined\n >;\n data?: MarkdownNodeData;\n children?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownRoot = {\n type: 'root';\n children: MarkdownNode[];\n};\n\ntype MarkdownEmbedDivProps =\n React.HTMLAttributes<HTMLDivElement> & {\n 'data-markdown-embed'?: string;\n 'data-markdown-embed-src'?: string;\n 'data-markdown-embed-label'?: string;\n };\n\nfunction normalizeHeadingLevelOffset(value: number | undefined) {\n if (value === undefined || !Number.isFinite(value)) {\n return 0;\n }\n\n return Math.max(0, Math.floor(value));\n}\n\nfunction getHeadingLevel(\n sourceLevel: number,\n offset: number,\n) {\n return Math.min(6, sourceLevel + offset);\n}\n\nfunction createTextNode(value: string): MarkdownNode {\n return {\n type: 'text',\n value,\n };\n}\n\nfunction appendNodesWithSeparator(\n target: MarkdownNode[],\n nodes: MarkdownNode[],\n) {\n if (nodes.length === 0) {\n return;\n }\n\n if (target.length > 0) {\n target.push(createTextNode(' '));\n }\n\n target.push(...nodes);\n}\n\nfunction getNodeText(node: MarkdownNode): string {\n if (typeof node.value === 'string') {\n return node.value;\n }\n\n return (node.children ?? [])\n .map(getNodeText)\n .join('');\n}\n\nfunction getEmbed(\n node: MarkdownNode,\n): MarkdownEmbed | null {\n if (\n node.type !== 'leafDirective' ||\n node.name !== 'embed'\n ) {\n return null;\n }\n\n const src = node.attributes?.src ?? '';\n const label = getNodeText(node);\n\n if (!src.trim() || !label.trim()) {\n return null;\n }\n\n return {\n src,\n label,\n };\n}\n\nfunction transformEmbedNodes(\n nodes: MarkdownNode[],\n) {\n for (const node of nodes) {\n if (\n node.type === 'leafDirective' &&\n node.name === 'embed'\n ) {\n const embed = getEmbed(node);\n\n node.data = {\n ...node.data,\n hName: 'div',\n hProperties: embed\n ? {\n 'data-markdown-embed': 'true',\n 'data-markdown-embed-src':\n embed.src,\n 'data-markdown-embed-label':\n embed.label,\n }\n : {\n 'data-markdown-embed':\n 'invalid',\n },\n hChildren: [],\n };\n\n continue;\n }\n\n if (node.children) {\n transformEmbedNodes(node.children);\n }\n }\n}\n\nconst remarkEmbed: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n\n transformEmbedNodes(root.children);\n };\n};\n\nfunction flattenInlineNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'html':\n return [];\n\n case 'break':\n return [\n createTextNode(' '),\n ];\n\n case 'image':\n case 'imageReference':\n return node.alt\n ? [\n createTextNode(node.alt),\n ]\n : [];\n\n default:\n if (!node.children) {\n return [\n node,\n ];\n }\n\n return [\n {\n ...node,\n children: node.children.flatMap(\n flattenInlineNode,\n ),\n },\n ];\n }\n}\n\nfunction flattenBlockNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'paragraph':\n case 'heading':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'tableCell':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'code':\n return node.value\n ? [\n {\n type: 'inlineCode',\n value: node.value,\n },\n ]\n : [];\n\n case 'leafDirective': {\n const embed = getEmbed(node);\n\n return embed\n ? [\n createTextNode(embed.label),\n ]\n : [];\n }\n\n case 'html':\n case 'definition':\n case 'footnoteDefinition':\n case 'thematicBreak':\n case 'yaml':\n return [];\n\n case 'blockquote':\n case 'list':\n case 'listItem':\n case 'table':\n case 'tableRow':\n return flattenBlockNodes(node.children ?? []);\n\n default:\n return node.children\n ? flattenBlockNodes(node.children)\n : [];\n }\n}\n\nfunction flattenBlockNodes(\n nodes: MarkdownNode[],\n): MarkdownNode[] {\n const result: MarkdownNode[] = [];\n\n for (const node of nodes) {\n appendNodesWithSeparator(\n result,\n flattenBlockNode(node),\n );\n }\n\n return result;\n}\n\nconst remarkExcerpt: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n const children = flattenBlockNodes(root.children);\n\n root.children = children.length > 0\n ? [\n {\n type: 'paragraph',\n children,\n },\n ]\n : [];\n };\n};\n\nconst MarkdownHeading: React.FC<MarkdownHeadingProps> = ({\n sourceLevel,\n offset,\n children,\n ...props\n}) => {\n const level = getHeadingLevel(sourceLevel, offset);\n\n switch (level) {\n case 1:\n return <h1 {...props}>{children}</h1>;\n\n case 2:\n return <h2 {...props}>{children}</h2>;\n\n case 3:\n return <h3 {...props}>{children}</h3>;\n\n case 4:\n return <h4 {...props}>{children}</h4>;\n\n case 5:\n return <h5 {...props}>{children}</h5>;\n\n default:\n return <h6 {...props}>{children}</h6>;\n }\n};\n\nfunction createDocumentComponents(\n headingLevelOffset: number,\n renderEmbed:\n | ((\n embed: MarkdownEmbed,\n ) => React.ReactNode)\n | undefined,\n): Components {\n return {\n h1: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={1}\n offset={headingLevelOffset}\n />\n ),\n\n h2: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={2}\n offset={headingLevelOffset}\n />\n ),\n\n h3: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={3}\n offset={headingLevelOffset}\n />\n ),\n\n h4: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={4}\n offset={headingLevelOffset}\n />\n ),\n\n h5: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={5}\n offset={headingLevelOffset}\n />\n ),\n\n h6: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={6}\n offset={headingLevelOffset}\n />\n ),\n\n div: ({\n node: _node,\n ...divProps\n }) => {\n const {\n 'data-markdown-embed':\n embedMarker,\n 'data-markdown-embed-src':\n embedSrc,\n 'data-markdown-embed-label':\n embedLabel,\n ...props\n } = divProps as MarkdownEmbedDivProps;\n\n if (embedMarker !== undefined) {\n if (\n embedMarker !== 'true' ||\n !embedSrc ||\n !embedLabel ||\n !renderEmbed\n ) {\n return null;\n }\n\n return renderEmbed({\n src: embedSrc,\n label: embedLabel,\n });\n }\n\n return <div {...props} />;\n },\n };\n}\n\nconst Markdown: React.FC<MarkdownProps> = ({\n content,\n excerpt = false,\n headingLevelOffset = 0,\n renderEmbed,\n className = '',\n ...props\n}) => {\n if (!content.trim()) {\n return null;\n }\n\n const classes = classnames('markdown', className, {\n 'markdown--excerpt': excerpt,\n });\n\n if (excerpt) {\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkDirective,\n remarkExcerpt,\n ]}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n }\n\n const normalizedHeadingLevelOffset =\n normalizeHeadingLevelOffset(headingLevelOffset);\n\n const documentComponents = createDocumentComponents(\n normalizedHeadingLevelOffset,\n renderEmbed,\n );\n\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkDirective,\n remarkEmbed,\n ]}\n components={documentComponents}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n};\n\nexport default Markdown;\n"]}
1
+ {"version":3,"sources":["../../../src/components/markdown/markdown.tsx"],"names":["jsx","classnames","ReactMarkdown","remarkGfm","remarkDirective"],"mappings":"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","file":"markdown.cjs","sourcesContent":["import React from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport remarkDirective from 'remark-directive';\nimport remarkGfm from 'remark-gfm';\nimport type { Plugin } from 'unified';\n\nimport './markdown.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface MarkdownEmbed {\n src: string;\n label: string;\n}\n\nexport type MarkdownLinkProps =\n React.AnchorHTMLAttributes<HTMLAnchorElement>;\n\nexport interface MarkdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children' | 'dangerouslySetInnerHTML'\n > {\n content: string;\n excerpt?: boolean;\n headingLevelOffset?: number;\n renderEmbed?: (\n embed: MarkdownEmbed,\n ) => React.ReactNode;\n renderLink?: (\n props: MarkdownLinkProps,\n ) => React.ReactNode;\n}\n\ninterface MarkdownHeadingProps\n extends React.HTMLAttributes<HTMLHeadingElement> {\n sourceLevel: number;\n offset: number;\n}\n\ntype MarkdownNodeData = {\n hName?: string;\n hProperties?: Record<string, unknown>;\n hChildren?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownNode = {\n type: string;\n name?: string;\n value?: string;\n alt?: string | null;\n attributes?: Record<\n string,\n string | null | undefined\n >;\n data?: MarkdownNodeData;\n children?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownRoot = {\n type: 'root';\n children: MarkdownNode[];\n};\n\ntype MarkdownEmbedDivProps =\n React.HTMLAttributes<HTMLDivElement> & {\n 'data-markdown-embed'?: string;\n 'data-markdown-embed-src'?: string;\n 'data-markdown-embed-label'?: string;\n };\n\nfunction normalizeHeadingLevelOffset(value: number | undefined) {\n if (value === undefined || !Number.isFinite(value)) {\n return 0;\n }\n\n return Math.max(0, Math.floor(value));\n}\n\nfunction getHeadingLevel(\n sourceLevel: number,\n offset: number,\n) {\n return Math.min(6, sourceLevel + offset);\n}\n\nfunction createTextNode(value: string): MarkdownNode {\n return {\n type: 'text',\n value,\n };\n}\n\nfunction appendNodesWithSeparator(\n target: MarkdownNode[],\n nodes: MarkdownNode[],\n) {\n if (nodes.length === 0) {\n return;\n }\n\n if (target.length > 0) {\n target.push(createTextNode(' '));\n }\n\n target.push(...nodes);\n}\n\nfunction getNodeText(node: MarkdownNode): string {\n if (typeof node.value === 'string') {\n return node.value;\n }\n\n return (node.children ?? [])\n .map(getNodeText)\n .join('');\n}\n\nfunction getEmbed(\n node: MarkdownNode,\n): MarkdownEmbed | null {\n if (\n node.type !== 'leafDirective' ||\n node.name !== 'embed'\n ) {\n return null;\n }\n\n const src = node.attributes?.src ?? '';\n const label = getNodeText(node);\n\n if (!src.trim() || !label.trim()) {\n return null;\n }\n\n return {\n src,\n label,\n };\n}\n\nfunction transformEmbedNodes(\n nodes: MarkdownNode[],\n) {\n for (const node of nodes) {\n if (\n node.type === 'leafDirective' &&\n node.name === 'embed'\n ) {\n const embed = getEmbed(node);\n\n node.data = {\n ...node.data,\n hName: 'div',\n hProperties: embed\n ? {\n 'data-markdown-embed': 'true',\n 'data-markdown-embed-src':\n embed.src,\n 'data-markdown-embed-label':\n embed.label,\n }\n : {\n 'data-markdown-embed':\n 'invalid',\n },\n hChildren: [],\n };\n\n continue;\n }\n\n if (node.children) {\n transformEmbedNodes(node.children);\n }\n }\n}\n\nconst remarkEmbed: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n\n transformEmbedNodes(root.children);\n };\n};\n\nfunction flattenInlineNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'html':\n return [];\n\n case 'break':\n return [\n createTextNode(' '),\n ];\n\n case 'image':\n case 'imageReference':\n return node.alt\n ? [\n createTextNode(node.alt),\n ]\n : [];\n\n default:\n if (!node.children) {\n return [\n node,\n ];\n }\n\n return [\n {\n ...node,\n children: node.children.flatMap(\n flattenInlineNode,\n ),\n },\n ];\n }\n}\n\nfunction flattenBlockNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'paragraph':\n case 'heading':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'tableCell':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'code':\n return node.value\n ? [\n {\n type: 'inlineCode',\n value: node.value,\n },\n ]\n : [];\n\n case 'leafDirective': {\n const embed = getEmbed(node);\n\n return embed\n ? [\n createTextNode(embed.label),\n ]\n : [];\n }\n\n case 'html':\n case 'definition':\n case 'footnoteDefinition':\n case 'thematicBreak':\n case 'yaml':\n return [];\n\n case 'blockquote':\n case 'list':\n case 'listItem':\n case 'table':\n case 'tableRow':\n return flattenBlockNodes(node.children ?? []);\n\n default:\n return node.children\n ? flattenBlockNodes(node.children)\n : [];\n }\n}\n\nfunction flattenBlockNodes(\n nodes: MarkdownNode[],\n): MarkdownNode[] {\n const result: MarkdownNode[] = [];\n\n for (const node of nodes) {\n appendNodesWithSeparator(\n result,\n flattenBlockNode(node),\n );\n }\n\n return result;\n}\n\nconst remarkExcerpt: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n const children = flattenBlockNodes(root.children);\n\n root.children = children.length > 0\n ? [\n {\n type: 'paragraph',\n children,\n },\n ]\n : [];\n };\n};\n\nconst MarkdownHeading: React.FC<MarkdownHeadingProps> = ({\n sourceLevel,\n offset,\n children,\n ...props\n}) => {\n const level = getHeadingLevel(sourceLevel, offset);\n\n switch (level) {\n case 1:\n return <h1 {...props}>{children}</h1>;\n\n case 2:\n return <h2 {...props}>{children}</h2>;\n\n case 3:\n return <h3 {...props}>{children}</h3>;\n\n case 4:\n return <h4 {...props}>{children}</h4>;\n\n case 5:\n return <h5 {...props}>{children}</h5>;\n\n default:\n return <h6 {...props}>{children}</h6>;\n }\n};\n\nfunction createDocumentComponents(\n headingLevelOffset: number,\n renderEmbed:\n | ((\n embed: MarkdownEmbed,\n ) => React.ReactNode)\n | undefined,\n renderLink:\n | ((\n props: MarkdownLinkProps,\n ) => React.ReactNode)\n | undefined,\n): Components {\n return {\n h1: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={1}\n offset={headingLevelOffset}\n />\n ),\n\n h2: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={2}\n offset={headingLevelOffset}\n />\n ),\n\n h3: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={3}\n offset={headingLevelOffset}\n />\n ),\n\n h4: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={4}\n offset={headingLevelOffset}\n />\n ),\n\n h5: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={5}\n offset={headingLevelOffset}\n />\n ),\n\n h6: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={6}\n offset={headingLevelOffset}\n />\n ),\n\n a: ({\n node: _node,\n ...linkProps\n }) => {\n if (renderLink) {\n return renderLink(linkProps);\n }\n\n return <a {...linkProps} />;\n },\n\n div: ({\n node: _node,\n ...divProps\n }) => {\n const {\n 'data-markdown-embed':\n embedMarker,\n 'data-markdown-embed-src':\n embedSrc,\n 'data-markdown-embed-label':\n embedLabel,\n ...props\n } = divProps as MarkdownEmbedDivProps;\n\n if (embedMarker !== undefined) {\n if (\n embedMarker !== 'true' ||\n !embedSrc ||\n !embedLabel ||\n !renderEmbed\n ) {\n return null;\n }\n\n return renderEmbed({\n src: embedSrc,\n label: embedLabel,\n });\n }\n\n return <div {...props} />;\n },\n };\n}\n\nconst Markdown: React.FC<MarkdownProps> = ({\n content,\n excerpt = false,\n headingLevelOffset = 0,\n renderEmbed,\n renderLink,\n className = '',\n ...props\n}) => {\n if (!content.trim()) {\n return null;\n }\n\n const classes = classnames('markdown', className, {\n 'markdown--excerpt': excerpt,\n });\n\n if (excerpt) {\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkDirective,\n remarkExcerpt,\n ]}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n }\n\n const normalizedHeadingLevelOffset =\n normalizeHeadingLevelOffset(headingLevelOffset);\n\n const documentComponents = createDocumentComponents(\n normalizedHeadingLevelOffset,\n renderEmbed,\n renderLink,\n );\n\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkDirective,\n remarkEmbed,\n ]}\n components={documentComponents}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n};\n\nexport default Markdown;\n"]}
@@ -4,11 +4,13 @@ export interface MarkdownEmbed {
4
4
  src: string;
5
5
  label: string;
6
6
  }
7
+ export type MarkdownLinkProps = React.AnchorHTMLAttributes<HTMLAnchorElement>;
7
8
  export interface MarkdownProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'dangerouslySetInnerHTML'> {
8
9
  content: string;
9
10
  excerpt?: boolean;
10
11
  headingLevelOffset?: number;
11
12
  renderEmbed?: (embed: MarkdownEmbed) => React.ReactNode;
13
+ renderLink?: (props: MarkdownLinkProps) => React.ReactNode;
12
14
  }
13
15
  declare const Markdown: React.FC<MarkdownProps>;
14
16
  export default Markdown;
@@ -191,7 +191,7 @@ const MarkdownHeading = ({
191
191
  return /* @__PURE__ */ jsx("h6", { ...props, children });
192
192
  }
193
193
  };
194
- function createDocumentComponents(headingLevelOffset, renderEmbed) {
194
+ function createDocumentComponents(headingLevelOffset, renderEmbed, renderLink) {
195
195
  return {
196
196
  h1: ({ node: _node, ...headingProps }) => /* @__PURE__ */ jsx(
197
197
  MarkdownHeading,
@@ -241,6 +241,15 @@ function createDocumentComponents(headingLevelOffset, renderEmbed) {
241
241
  offset: headingLevelOffset
242
242
  }
243
243
  ),
244
+ a: ({
245
+ node: _node,
246
+ ...linkProps
247
+ }) => {
248
+ if (renderLink) {
249
+ return renderLink(linkProps);
250
+ }
251
+ return /* @__PURE__ */ jsx("a", { ...linkProps });
252
+ },
244
253
  div: ({
245
254
  node: _node,
246
255
  ...divProps
@@ -269,6 +278,7 @@ const Markdown = ({
269
278
  excerpt = false,
270
279
  headingLevelOffset = 0,
271
280
  renderEmbed,
281
+ renderLink,
272
282
  className = "",
273
283
  ...props
274
284
  }) => {
@@ -301,7 +311,8 @@ const Markdown = ({
301
311
  const normalizedHeadingLevelOffset = normalizeHeadingLevelOffset(headingLevelOffset);
302
312
  const documentComponents = createDocumentComponents(
303
313
  normalizedHeadingLevelOffset,
304
- renderEmbed
314
+ renderEmbed,
315
+ renderLink
305
316
  );
306
317
  return /* @__PURE__ */ jsx(
307
318
  "div",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/markdown/markdown.tsx"],"names":[],"mappings":"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","file":"markdown.js","sourcesContent":["import React from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport remarkDirective from 'remark-directive';\nimport remarkGfm from 'remark-gfm';\nimport type { Plugin } from 'unified';\n\nimport './markdown.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface MarkdownEmbed {\n src: string;\n label: string;\n}\n\nexport interface MarkdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children' | 'dangerouslySetInnerHTML'\n > {\n content: string;\n excerpt?: boolean;\n headingLevelOffset?: number;\n renderEmbed?: (\n embed: MarkdownEmbed,\n ) => React.ReactNode;\n}\n\ninterface MarkdownHeadingProps\n extends React.HTMLAttributes<HTMLHeadingElement> {\n sourceLevel: number;\n offset: number;\n}\n\ntype MarkdownNodeData = {\n hName?: string;\n hProperties?: Record<string, unknown>;\n hChildren?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownNode = {\n type: string;\n name?: string;\n value?: string;\n alt?: string | null;\n attributes?: Record<\n string,\n string | null | undefined\n >;\n data?: MarkdownNodeData;\n children?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownRoot = {\n type: 'root';\n children: MarkdownNode[];\n};\n\ntype MarkdownEmbedDivProps =\n React.HTMLAttributes<HTMLDivElement> & {\n 'data-markdown-embed'?: string;\n 'data-markdown-embed-src'?: string;\n 'data-markdown-embed-label'?: string;\n };\n\nfunction normalizeHeadingLevelOffset(value: number | undefined) {\n if (value === undefined || !Number.isFinite(value)) {\n return 0;\n }\n\n return Math.max(0, Math.floor(value));\n}\n\nfunction getHeadingLevel(\n sourceLevel: number,\n offset: number,\n) {\n return Math.min(6, sourceLevel + offset);\n}\n\nfunction createTextNode(value: string): MarkdownNode {\n return {\n type: 'text',\n value,\n };\n}\n\nfunction appendNodesWithSeparator(\n target: MarkdownNode[],\n nodes: MarkdownNode[],\n) {\n if (nodes.length === 0) {\n return;\n }\n\n if (target.length > 0) {\n target.push(createTextNode(' '));\n }\n\n target.push(...nodes);\n}\n\nfunction getNodeText(node: MarkdownNode): string {\n if (typeof node.value === 'string') {\n return node.value;\n }\n\n return (node.children ?? [])\n .map(getNodeText)\n .join('');\n}\n\nfunction getEmbed(\n node: MarkdownNode,\n): MarkdownEmbed | null {\n if (\n node.type !== 'leafDirective' ||\n node.name !== 'embed'\n ) {\n return null;\n }\n\n const src = node.attributes?.src ?? '';\n const label = getNodeText(node);\n\n if (!src.trim() || !label.trim()) {\n return null;\n }\n\n return {\n src,\n label,\n };\n}\n\nfunction transformEmbedNodes(\n nodes: MarkdownNode[],\n) {\n for (const node of nodes) {\n if (\n node.type === 'leafDirective' &&\n node.name === 'embed'\n ) {\n const embed = getEmbed(node);\n\n node.data = {\n ...node.data,\n hName: 'div',\n hProperties: embed\n ? {\n 'data-markdown-embed': 'true',\n 'data-markdown-embed-src':\n embed.src,\n 'data-markdown-embed-label':\n embed.label,\n }\n : {\n 'data-markdown-embed':\n 'invalid',\n },\n hChildren: [],\n };\n\n continue;\n }\n\n if (node.children) {\n transformEmbedNodes(node.children);\n }\n }\n}\n\nconst remarkEmbed: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n\n transformEmbedNodes(root.children);\n };\n};\n\nfunction flattenInlineNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'html':\n return [];\n\n case 'break':\n return [\n createTextNode(' '),\n ];\n\n case 'image':\n case 'imageReference':\n return node.alt\n ? [\n createTextNode(node.alt),\n ]\n : [];\n\n default:\n if (!node.children) {\n return [\n node,\n ];\n }\n\n return [\n {\n ...node,\n children: node.children.flatMap(\n flattenInlineNode,\n ),\n },\n ];\n }\n}\n\nfunction flattenBlockNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'paragraph':\n case 'heading':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'tableCell':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'code':\n return node.value\n ? [\n {\n type: 'inlineCode',\n value: node.value,\n },\n ]\n : [];\n\n case 'leafDirective': {\n const embed = getEmbed(node);\n\n return embed\n ? [\n createTextNode(embed.label),\n ]\n : [];\n }\n\n case 'html':\n case 'definition':\n case 'footnoteDefinition':\n case 'thematicBreak':\n case 'yaml':\n return [];\n\n case 'blockquote':\n case 'list':\n case 'listItem':\n case 'table':\n case 'tableRow':\n return flattenBlockNodes(node.children ?? []);\n\n default:\n return node.children\n ? flattenBlockNodes(node.children)\n : [];\n }\n}\n\nfunction flattenBlockNodes(\n nodes: MarkdownNode[],\n): MarkdownNode[] {\n const result: MarkdownNode[] = [];\n\n for (const node of nodes) {\n appendNodesWithSeparator(\n result,\n flattenBlockNode(node),\n );\n }\n\n return result;\n}\n\nconst remarkExcerpt: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n const children = flattenBlockNodes(root.children);\n\n root.children = children.length > 0\n ? [\n {\n type: 'paragraph',\n children,\n },\n ]\n : [];\n };\n};\n\nconst MarkdownHeading: React.FC<MarkdownHeadingProps> = ({\n sourceLevel,\n offset,\n children,\n ...props\n}) => {\n const level = getHeadingLevel(sourceLevel, offset);\n\n switch (level) {\n case 1:\n return <h1 {...props}>{children}</h1>;\n\n case 2:\n return <h2 {...props}>{children}</h2>;\n\n case 3:\n return <h3 {...props}>{children}</h3>;\n\n case 4:\n return <h4 {...props}>{children}</h4>;\n\n case 5:\n return <h5 {...props}>{children}</h5>;\n\n default:\n return <h6 {...props}>{children}</h6>;\n }\n};\n\nfunction createDocumentComponents(\n headingLevelOffset: number,\n renderEmbed:\n | ((\n embed: MarkdownEmbed,\n ) => React.ReactNode)\n | undefined,\n): Components {\n return {\n h1: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={1}\n offset={headingLevelOffset}\n />\n ),\n\n h2: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={2}\n offset={headingLevelOffset}\n />\n ),\n\n h3: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={3}\n offset={headingLevelOffset}\n />\n ),\n\n h4: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={4}\n offset={headingLevelOffset}\n />\n ),\n\n h5: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={5}\n offset={headingLevelOffset}\n />\n ),\n\n h6: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={6}\n offset={headingLevelOffset}\n />\n ),\n\n div: ({\n node: _node,\n ...divProps\n }) => {\n const {\n 'data-markdown-embed':\n embedMarker,\n 'data-markdown-embed-src':\n embedSrc,\n 'data-markdown-embed-label':\n embedLabel,\n ...props\n } = divProps as MarkdownEmbedDivProps;\n\n if (embedMarker !== undefined) {\n if (\n embedMarker !== 'true' ||\n !embedSrc ||\n !embedLabel ||\n !renderEmbed\n ) {\n return null;\n }\n\n return renderEmbed({\n src: embedSrc,\n label: embedLabel,\n });\n }\n\n return <div {...props} />;\n },\n };\n}\n\nconst Markdown: React.FC<MarkdownProps> = ({\n content,\n excerpt = false,\n headingLevelOffset = 0,\n renderEmbed,\n className = '',\n ...props\n}) => {\n if (!content.trim()) {\n return null;\n }\n\n const classes = classnames('markdown', className, {\n 'markdown--excerpt': excerpt,\n });\n\n if (excerpt) {\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkDirective,\n remarkExcerpt,\n ]}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n }\n\n const normalizedHeadingLevelOffset =\n normalizeHeadingLevelOffset(headingLevelOffset);\n\n const documentComponents = createDocumentComponents(\n normalizedHeadingLevelOffset,\n renderEmbed,\n );\n\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkDirective,\n remarkEmbed,\n ]}\n components={documentComponents}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n};\n\nexport default Markdown;\n"]}
1
+ {"version":3,"sources":["../../../src/components/markdown/markdown.tsx"],"names":[],"mappings":"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","file":"markdown.js","sourcesContent":["import React from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport remarkDirective from 'remark-directive';\nimport remarkGfm from 'remark-gfm';\nimport type { Plugin } from 'unified';\n\nimport './markdown.css';\nimport { classnames } from '../helpers/classnames';\n\nexport interface MarkdownEmbed {\n src: string;\n label: string;\n}\n\nexport type MarkdownLinkProps =\n React.AnchorHTMLAttributes<HTMLAnchorElement>;\n\nexport interface MarkdownProps\n extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'children' | 'dangerouslySetInnerHTML'\n > {\n content: string;\n excerpt?: boolean;\n headingLevelOffset?: number;\n renderEmbed?: (\n embed: MarkdownEmbed,\n ) => React.ReactNode;\n renderLink?: (\n props: MarkdownLinkProps,\n ) => React.ReactNode;\n}\n\ninterface MarkdownHeadingProps\n extends React.HTMLAttributes<HTMLHeadingElement> {\n sourceLevel: number;\n offset: number;\n}\n\ntype MarkdownNodeData = {\n hName?: string;\n hProperties?: Record<string, unknown>;\n hChildren?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownNode = {\n type: string;\n name?: string;\n value?: string;\n alt?: string | null;\n attributes?: Record<\n string,\n string | null | undefined\n >;\n data?: MarkdownNodeData;\n children?: MarkdownNode[];\n [key: string]: unknown;\n};\n\ntype MarkdownRoot = {\n type: 'root';\n children: MarkdownNode[];\n};\n\ntype MarkdownEmbedDivProps =\n React.HTMLAttributes<HTMLDivElement> & {\n 'data-markdown-embed'?: string;\n 'data-markdown-embed-src'?: string;\n 'data-markdown-embed-label'?: string;\n };\n\nfunction normalizeHeadingLevelOffset(value: number | undefined) {\n if (value === undefined || !Number.isFinite(value)) {\n return 0;\n }\n\n return Math.max(0, Math.floor(value));\n}\n\nfunction getHeadingLevel(\n sourceLevel: number,\n offset: number,\n) {\n return Math.min(6, sourceLevel + offset);\n}\n\nfunction createTextNode(value: string): MarkdownNode {\n return {\n type: 'text',\n value,\n };\n}\n\nfunction appendNodesWithSeparator(\n target: MarkdownNode[],\n nodes: MarkdownNode[],\n) {\n if (nodes.length === 0) {\n return;\n }\n\n if (target.length > 0) {\n target.push(createTextNode(' '));\n }\n\n target.push(...nodes);\n}\n\nfunction getNodeText(node: MarkdownNode): string {\n if (typeof node.value === 'string') {\n return node.value;\n }\n\n return (node.children ?? [])\n .map(getNodeText)\n .join('');\n}\n\nfunction getEmbed(\n node: MarkdownNode,\n): MarkdownEmbed | null {\n if (\n node.type !== 'leafDirective' ||\n node.name !== 'embed'\n ) {\n return null;\n }\n\n const src = node.attributes?.src ?? '';\n const label = getNodeText(node);\n\n if (!src.trim() || !label.trim()) {\n return null;\n }\n\n return {\n src,\n label,\n };\n}\n\nfunction transformEmbedNodes(\n nodes: MarkdownNode[],\n) {\n for (const node of nodes) {\n if (\n node.type === 'leafDirective' &&\n node.name === 'embed'\n ) {\n const embed = getEmbed(node);\n\n node.data = {\n ...node.data,\n hName: 'div',\n hProperties: embed\n ? {\n 'data-markdown-embed': 'true',\n 'data-markdown-embed-src':\n embed.src,\n 'data-markdown-embed-label':\n embed.label,\n }\n : {\n 'data-markdown-embed':\n 'invalid',\n },\n hChildren: [],\n };\n\n continue;\n }\n\n if (node.children) {\n transformEmbedNodes(node.children);\n }\n }\n}\n\nconst remarkEmbed: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n\n transformEmbedNodes(root.children);\n };\n};\n\nfunction flattenInlineNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'html':\n return [];\n\n case 'break':\n return [\n createTextNode(' '),\n ];\n\n case 'image':\n case 'imageReference':\n return node.alt\n ? [\n createTextNode(node.alt),\n ]\n : [];\n\n default:\n if (!node.children) {\n return [\n node,\n ];\n }\n\n return [\n {\n ...node,\n children: node.children.flatMap(\n flattenInlineNode,\n ),\n },\n ];\n }\n}\n\nfunction flattenBlockNode(\n node: MarkdownNode,\n): MarkdownNode[] {\n switch (node.type) {\n case 'paragraph':\n case 'heading':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'tableCell':\n return (node.children ?? []).flatMap(\n flattenInlineNode,\n );\n\n case 'code':\n return node.value\n ? [\n {\n type: 'inlineCode',\n value: node.value,\n },\n ]\n : [];\n\n case 'leafDirective': {\n const embed = getEmbed(node);\n\n return embed\n ? [\n createTextNode(embed.label),\n ]\n : [];\n }\n\n case 'html':\n case 'definition':\n case 'footnoteDefinition':\n case 'thematicBreak':\n case 'yaml':\n return [];\n\n case 'blockquote':\n case 'list':\n case 'listItem':\n case 'table':\n case 'tableRow':\n return flattenBlockNodes(node.children ?? []);\n\n default:\n return node.children\n ? flattenBlockNodes(node.children)\n : [];\n }\n}\n\nfunction flattenBlockNodes(\n nodes: MarkdownNode[],\n): MarkdownNode[] {\n const result: MarkdownNode[] = [];\n\n for (const node of nodes) {\n appendNodesWithSeparator(\n result,\n flattenBlockNode(node),\n );\n }\n\n return result;\n}\n\nconst remarkExcerpt: Plugin = () => {\n return (tree) => {\n const root = tree as MarkdownRoot;\n const children = flattenBlockNodes(root.children);\n\n root.children = children.length > 0\n ? [\n {\n type: 'paragraph',\n children,\n },\n ]\n : [];\n };\n};\n\nconst MarkdownHeading: React.FC<MarkdownHeadingProps> = ({\n sourceLevel,\n offset,\n children,\n ...props\n}) => {\n const level = getHeadingLevel(sourceLevel, offset);\n\n switch (level) {\n case 1:\n return <h1 {...props}>{children}</h1>;\n\n case 2:\n return <h2 {...props}>{children}</h2>;\n\n case 3:\n return <h3 {...props}>{children}</h3>;\n\n case 4:\n return <h4 {...props}>{children}</h4>;\n\n case 5:\n return <h5 {...props}>{children}</h5>;\n\n default:\n return <h6 {...props}>{children}</h6>;\n }\n};\n\nfunction createDocumentComponents(\n headingLevelOffset: number,\n renderEmbed:\n | ((\n embed: MarkdownEmbed,\n ) => React.ReactNode)\n | undefined,\n renderLink:\n | ((\n props: MarkdownLinkProps,\n ) => React.ReactNode)\n | undefined,\n): Components {\n return {\n h1: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={1}\n offset={headingLevelOffset}\n />\n ),\n\n h2: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={2}\n offset={headingLevelOffset}\n />\n ),\n\n h3: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={3}\n offset={headingLevelOffset}\n />\n ),\n\n h4: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={4}\n offset={headingLevelOffset}\n />\n ),\n\n h5: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={5}\n offset={headingLevelOffset}\n />\n ),\n\n h6: ({ node: _node, ...headingProps }) => (\n <MarkdownHeading\n {...headingProps}\n sourceLevel={6}\n offset={headingLevelOffset}\n />\n ),\n\n a: ({\n node: _node,\n ...linkProps\n }) => {\n if (renderLink) {\n return renderLink(linkProps);\n }\n\n return <a {...linkProps} />;\n },\n\n div: ({\n node: _node,\n ...divProps\n }) => {\n const {\n 'data-markdown-embed':\n embedMarker,\n 'data-markdown-embed-src':\n embedSrc,\n 'data-markdown-embed-label':\n embedLabel,\n ...props\n } = divProps as MarkdownEmbedDivProps;\n\n if (embedMarker !== undefined) {\n if (\n embedMarker !== 'true' ||\n !embedSrc ||\n !embedLabel ||\n !renderEmbed\n ) {\n return null;\n }\n\n return renderEmbed({\n src: embedSrc,\n label: embedLabel,\n });\n }\n\n return <div {...props} />;\n },\n };\n}\n\nconst Markdown: React.FC<MarkdownProps> = ({\n content,\n excerpt = false,\n headingLevelOffset = 0,\n renderEmbed,\n renderLink,\n className = '',\n ...props\n}) => {\n if (!content.trim()) {\n return null;\n }\n\n const classes = classnames('markdown', className, {\n 'markdown--excerpt': excerpt,\n });\n\n if (excerpt) {\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkDirective,\n remarkExcerpt,\n ]}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n }\n\n const normalizedHeadingLevelOffset =\n normalizeHeadingLevelOffset(headingLevelOffset);\n\n const documentComponents = createDocumentComponents(\n normalizedHeadingLevelOffset,\n renderEmbed,\n renderLink,\n );\n\n return (\n <div\n className={classes}\n {...props}\n >\n <ReactMarkdown\n remarkPlugins={[\n remarkGfm,\n remarkDirective,\n remarkEmbed,\n ]}\n components={documentComponents}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n};\n\nexport default Markdown;\n"]}
package/index.cjs CHANGED
@@ -223,6 +223,10 @@ Object.defineProperty(exports, "CourseOutline", {
223
223
  enumerable: true,
224
224
  get: function () { return courseOutline__default.default; }
225
225
  });
226
+ Object.defineProperty(exports, "CourseOutlineItem", {
227
+ enumerable: true,
228
+ get: function () { return courseOutline.CourseOutlineItem; }
229
+ });
226
230
  Object.defineProperty(exports, "FlipList", {
227
231
  enumerable: true,
228
232
  get: function () { return flipList__default.default; }
package/index.d.ts CHANGED
@@ -58,11 +58,11 @@ export type { CardGroupProps } from './components/card-group';
58
58
  export { default as Breadcrumbs } from './components/breadcrumbs';
59
59
  export type { BreadcrumbItem, BreadcrumbsPresentation, BreadcrumbsProps, } from './components/breadcrumbs';
60
60
  export { default as Markdown } from './components/markdown';
61
- export type { MarkdownEmbed, MarkdownProps, } from './components/markdown';
61
+ export type { MarkdownEmbed, MarkdownLinkProps, MarkdownProps, } from './components/markdown';
62
62
  export { default as Discussion } from './components/discussion';
63
63
  export type { DiscussionItem, DiscussionProps, } from './components/discussion';
64
- export { default as CourseOutline } from './components/course-outline';
65
- export type { CourseOutlineGroup, CourseOutlineHeadingLevel, CourseOutlineItem, CourseOutlineProps, } from './components/course-outline';
64
+ export { default as CourseOutline, CourseOutlineItem, } from './components/course-outline';
65
+ export type { CourseOutlineGroup, CourseOutlineHeadingLevel, CourseOutlineItemProps, CourseOutlineProps, } from './components/course-outline';
66
66
  export * from './components/calendar-month';
67
67
  export { default as FlipList } from './components/flip-list';
68
68
  export type { FlipListItem, FlipListProps, } from './components/flip-list';
package/index.js CHANGED
@@ -27,7 +27,7 @@ export { default as CardGroup } from './components/card-group';
27
27
  export { default as Breadcrumbs } from './components/breadcrumbs';
28
28
  export { default as Markdown } from './components/markdown';
29
29
  export { default as Discussion } from './components/discussion';
30
- export { default as CourseOutline } from './components/course-outline';
30
+ export { default as CourseOutline, CourseOutlineItem } from './components/course-outline';
31
31
  export * from './components/calendar-month';
32
32
  export { default as FlipList } from './components/flip-list';
33
33
  export { default as AvatarUpload } from './components/avatar-upload';
@@ -176,7 +176,7 @@
176
176
  /* typography */
177
177
 
178
178
  /* size */
179
- --layout-base-content-width: 1200px;
179
+ --layout-base-content-width: 1920px;
180
180
 
181
181
  /* border */
182
182
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jvetrau-ds",
3
- "version": "0.2.47",
3
+ "version": "0.2.49",
4
4
  "description": "Multi-brand React design system with semantic tokens",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",