@placeholderco/placeholder-ui 1.0.12 → 2.0.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 (276) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +134 -130
  3. package/dist/app.css +178 -0
  4. package/dist/bootstrap.min.css +3600 -0
  5. package/dist/cards/GitCard.svelte +115 -0
  6. package/dist/cards/GitCard.svelte.d.ts +22 -0
  7. package/dist/display/Avatar.svelte +29 -17
  8. package/dist/display/Avatar.svelte.d.ts +12 -2
  9. package/dist/display/LinkCollection.svelte +40 -18
  10. package/dist/display/LinkCollection.svelte.d.ts +9 -2
  11. package/dist/display/Paper.svelte +31 -19
  12. package/dist/display/Paper.svelte.d.ts +12 -3
  13. package/dist/display/alert/Alert.svelte +129 -0
  14. package/dist/display/alert/Alert.svelte.d.ts +15 -0
  15. package/dist/display/alert/AlertVariant.d.ts +1 -0
  16. package/dist/display/alert/AlertVariant.js +1 -0
  17. package/dist/display/filetree/FileTree.svelte +259 -0
  18. package/dist/display/filetree/FileTree.svelte.d.ts +76 -0
  19. package/dist/display/filetree/FileTreeItem.svelte +396 -0
  20. package/dist/display/filetree/FileTreeItem.svelte.d.ts +40 -0
  21. package/dist/display/filetree/FileTreeNode.d.ts +46 -0
  22. package/dist/display/filetree/FileTreeNode.js +115 -0
  23. package/dist/display/filetree/index.d.ts +5 -0
  24. package/dist/display/filetree/index.js +3 -0
  25. package/dist/editors/CodeMirror.svelte +306 -0
  26. package/dist/editors/CodeMirror.svelte.d.ts +31 -0
  27. package/dist/editors/tiptap/LinkActionMenu.svelte +307 -0
  28. package/dist/editors/tiptap/LinkActionMenu.svelte.d.ts +8 -0
  29. package/dist/editors/tiptap/TipTap.svelte +856 -0
  30. package/dist/editors/tiptap/TipTap.svelte.d.ts +54 -0
  31. package/dist/editors/tiptap/TipTapBubble.svelte +790 -0
  32. package/dist/editors/tiptap/TipTapBubble.svelte.d.ts +44 -0
  33. package/dist/editors/tiptap/collaboration.d.ts +55 -0
  34. package/dist/editors/tiptap/collaboration.js +1 -0
  35. package/dist/editors/tiptap/extensions/Alert.d.ts +18 -0
  36. package/dist/editors/tiptap/extensions/Alert.js +72 -0
  37. package/dist/editors/tiptap/extensions/CodeBlockEditor.d.ts +21 -0
  38. package/dist/editors/tiptap/extensions/CodeBlockEditor.js +326 -0
  39. package/dist/editors/tiptap/extensions/Div.d.ts +19 -0
  40. package/dist/editors/tiptap/extensions/Div.js +89 -0
  41. package/dist/editors/tiptap/extensions/Span.d.ts +5 -0
  42. package/dist/editors/tiptap/extensions/Span.js +56 -0
  43. package/dist/editors/tiptap/extensions/codeBlockEditor.css +236 -0
  44. package/dist/editors/tiptap/extensions/codeBlockLanguages.d.ts +17 -0
  45. package/dist/editors/tiptap/extensions/codeBlockLanguages.js +124 -0
  46. package/dist/editors/tiptap/extensions/index.d.ts +7 -0
  47. package/dist/editors/tiptap/extensions/index.js +5 -0
  48. package/dist/editors/tiptap/toolbar/AlertButton.svelte +261 -0
  49. package/dist/editors/tiptap/toolbar/AlertButton.svelte.d.ts +7 -0
  50. package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte +18 -0
  51. package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte.d.ts +7 -0
  52. package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte +18 -0
  53. package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte.d.ts +7 -0
  54. package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte +18 -0
  55. package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte.d.ts +7 -0
  56. package/dist/editors/tiptap/toolbar/AlignRightButton.svelte +18 -0
  57. package/dist/editors/tiptap/toolbar/AlignRightButton.svelte.d.ts +7 -0
  58. package/dist/editors/tiptap/toolbar/BoldButton.svelte +18 -0
  59. package/dist/editors/tiptap/toolbar/BoldButton.svelte.d.ts +7 -0
  60. package/dist/editors/tiptap/toolbar/BulletListButton.svelte +18 -0
  61. package/dist/editors/tiptap/toolbar/BulletListButton.svelte.d.ts +7 -0
  62. package/dist/editors/tiptap/toolbar/CodeBlockButton.svelte +18 -0
  63. package/dist/editors/tiptap/toolbar/CodeBlockButton.svelte.d.ts +7 -0
  64. package/dist/editors/tiptap/toolbar/CodeButton.svelte +18 -0
  65. package/dist/editors/tiptap/toolbar/CodeButton.svelte.d.ts +7 -0
  66. package/dist/editors/tiptap/toolbar/ColorButton.svelte +299 -0
  67. package/dist/editors/tiptap/toolbar/ColorButton.svelte.d.ts +20 -0
  68. package/dist/editors/tiptap/toolbar/DocumentButton.svelte +58 -0
  69. package/dist/editors/tiptap/toolbar/DocumentButton.svelte.d.ts +9 -0
  70. package/dist/editors/tiptap/toolbar/HeadingButton.svelte +30 -0
  71. package/dist/editors/tiptap/toolbar/HeadingButton.svelte.d.ts +8 -0
  72. package/dist/editors/tiptap/toolbar/HtmlButton.svelte +68 -0
  73. package/dist/editors/tiptap/toolbar/HtmlButton.svelte.d.ts +7 -0
  74. package/dist/editors/tiptap/toolbar/ImageButton.svelte +54 -0
  75. package/dist/editors/tiptap/toolbar/ImageButton.svelte.d.ts +8 -0
  76. package/dist/editors/tiptap/toolbar/ItalicButton.svelte +18 -0
  77. package/dist/editors/tiptap/toolbar/ItalicButton.svelte.d.ts +7 -0
  78. package/dist/editors/tiptap/toolbar/LinkButton.svelte +257 -0
  79. package/dist/editors/tiptap/toolbar/LinkButton.svelte.d.ts +7 -0
  80. package/dist/editors/tiptap/toolbar/OrderedListButton.svelte +18 -0
  81. package/dist/editors/tiptap/toolbar/OrderedListButton.svelte.d.ts +7 -0
  82. package/dist/editors/tiptap/toolbar/RedoButton.svelte +18 -0
  83. package/dist/editors/tiptap/toolbar/RedoButton.svelte.d.ts +7 -0
  84. package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte +18 -0
  85. package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte.d.ts +7 -0
  86. package/dist/editors/tiptap/toolbar/SubscriptButton.svelte +18 -0
  87. package/dist/editors/tiptap/toolbar/SubscriptButton.svelte.d.ts +7 -0
  88. package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte +18 -0
  89. package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte.d.ts +7 -0
  90. package/dist/editors/tiptap/toolbar/TableButton.svelte +258 -0
  91. package/dist/editors/tiptap/toolbar/TableButton.svelte.d.ts +7 -0
  92. package/dist/editors/tiptap/toolbar/ToolbarButton.svelte +84 -0
  93. package/dist/editors/tiptap/toolbar/ToolbarButton.svelte.d.ts +10 -0
  94. package/dist/editors/tiptap/toolbar/UnderlineButton.svelte +18 -0
  95. package/dist/editors/tiptap/toolbar/UnderlineButton.svelte.d.ts +7 -0
  96. package/dist/editors/tiptap/toolbar/UndoButton.svelte +18 -0
  97. package/dist/editors/tiptap/toolbar/UndoButton.svelte.d.ts +7 -0
  98. package/dist/form/Autocomplete.svelte +86 -135
  99. package/dist/form/Autocomplete.svelte.d.ts +6 -8
  100. package/dist/form/AutocompleteMulti.svelte +385 -227
  101. package/dist/form/AutocompleteMulti.svelte.d.ts +59 -10
  102. package/dist/form/Checkbox.svelte +59 -54
  103. package/dist/form/Checkbox.svelte.d.ts +14 -5
  104. package/dist/form/Chips.svelte +29 -13
  105. package/dist/form/Chips.svelte.d.ts +16 -2
  106. package/dist/form/ComboBox.svelte +30 -20
  107. package/dist/form/ComboBox.svelte.d.ts +1 -1
  108. package/dist/form/ComboBoxItemBuilder.svelte +161 -188
  109. package/dist/form/ComboBoxItemBuilder.svelte.d.ts +19 -2
  110. package/dist/form/ComboBoxMulti.svelte +38 -24
  111. package/dist/form/ComboBoxMulti.svelte.d.ts +1 -1
  112. package/dist/form/CronBuilder.svelte +84 -67
  113. package/dist/form/CronBuilder.svelte.d.ts +16 -3
  114. package/dist/form/DatePicker.svelte +148 -195
  115. package/dist/form/DateRangePicker.svelte +101 -98
  116. package/dist/form/DateTimePicker.svelte +167 -208
  117. package/dist/form/DateTimePicker.svelte.d.ts +10 -2
  118. package/dist/form/FormGroup.svelte +33 -10
  119. package/dist/form/FormGroup.svelte.d.ts +12 -2
  120. package/dist/form/Number.svelte +70 -47
  121. package/dist/form/Number.svelte.d.ts +36 -6
  122. package/dist/form/Radio.svelte +18 -18
  123. package/dist/form/RadioGroup.svelte +23 -12
  124. package/dist/form/RadioGroup.svelte.d.ts +13 -2
  125. package/dist/form/SegmentedControl.svelte +76 -56
  126. package/dist/form/SegmentedControl.svelte.d.ts +9 -4
  127. package/dist/form/Select.svelte +150 -233
  128. package/dist/form/Select.svelte.d.ts +29 -5
  129. package/dist/form/SelectMulti.svelte +163 -277
  130. package/dist/form/SelectMulti.svelte.d.ts +36 -7
  131. package/dist/form/Slider.svelte +183 -269
  132. package/dist/form/Slider.svelte.d.ts +32 -17
  133. package/dist/form/StringArrayBuilder.svelte +249 -0
  134. package/dist/form/StringArrayBuilder.svelte.d.ts +15 -0
  135. package/dist/form/Switch.svelte +164 -106
  136. package/dist/form/Switch.svelte.d.ts +22 -3
  137. package/dist/form/TextArea.svelte +49 -29
  138. package/dist/form/TextArea.svelte.d.ts +23 -3
  139. package/dist/form/Textbox.svelte +69 -68
  140. package/dist/form/Textbox.svelte.d.ts +32 -4
  141. package/dist/form/TimePicker.svelte +42 -47
  142. package/dist/form/TimePicker.svelte.d.ts +12 -2
  143. package/dist/form/comboBoxCore.svelte.d.ts +99 -0
  144. package/dist/form/comboBoxCore.svelte.js +243 -0
  145. package/dist/icon/Icon.svelte +8 -3
  146. package/dist/icon/Icon.svelte.d.ts +8 -3
  147. package/dist/icon/file-type-bmp.svg +1 -0
  148. package/dist/icon/file-type-csv.svg +1 -0
  149. package/dist/icon/file-type-doc.svg +1 -0
  150. package/dist/icon/file-type-docx.svg +1 -0
  151. package/dist/icon/file-type-jpg.svg +1 -0
  152. package/dist/icon/file-type-pdf.svg +1 -0
  153. package/dist/icon/file-type-png.svg +1 -0
  154. package/dist/icon/file-type-ppt.svg +1 -0
  155. package/dist/icon/file-type-svg.svg +1 -0
  156. package/dist/icon/file-type-txt.svg +1 -0
  157. package/dist/icon/file-type-xls.svg +1 -0
  158. package/dist/icon/file-type-zip.svg +1 -0
  159. package/dist/icon/index.d.ts +166 -151
  160. package/dist/icon/index.js +166 -152
  161. package/dist/icon/logo-placeholder.svg +6 -0
  162. package/dist/icon/source-code.svg +1 -0
  163. package/dist/icon/sun-moon.svg +1 -0
  164. package/dist/icon/table.svg +6 -0
  165. package/dist/index.d.ts +87 -26
  166. package/dist/index.js +25 -28
  167. package/dist/layout/AppShell.svelte +12 -162
  168. package/dist/layout/AppShell.svelte.d.ts +6 -27
  169. package/dist/layout/CustomNavbar.svelte +9 -7
  170. package/dist/layout/CustomNavbar.svelte.d.ts +4 -2
  171. package/dist/layout/Navbar.svelte +161 -129
  172. package/dist/layout/Navbar.svelte.d.ts +29 -15
  173. package/dist/layout/NavbarItemDisplay.svelte +2 -2
  174. package/dist/layout/NavbarItemView.svelte +182 -0
  175. package/dist/layout/NavbarItemView.svelte.d.ts +10 -0
  176. package/dist/layout/Sidenav.svelte +280 -341
  177. package/dist/layout/Sidenav.svelte.d.ts +36 -4
  178. package/dist/models/ComboBoxItem.d.ts +2 -0
  179. package/dist/models/Employee.d.ts +53 -0
  180. package/dist/models/Employee.js +23 -0
  181. package/dist/models/Hyperlink.d.ts +3 -1
  182. package/dist/models/LinkCollectionItem.d.ts +3 -1
  183. package/dist/models/NavbarItem.d.ts +6 -2
  184. package/dist/theme.svelte.d.ts +0 -1
  185. package/dist/theme.svelte.js +46 -58
  186. package/dist/ui/Accordion.svelte +81 -242
  187. package/dist/ui/Accordion.svelte.d.ts +37 -14
  188. package/dist/ui/AccordionItem.svelte +303 -0
  189. package/dist/ui/AccordionItem.svelte.d.ts +21 -0
  190. package/dist/ui/ActionIcon.svelte +25 -21
  191. package/dist/ui/ActionIcon.svelte.d.ts +15 -2
  192. package/dist/ui/Badge.svelte +163 -171
  193. package/dist/ui/Badge.svelte.d.ts +13 -5
  194. package/dist/ui/Button.svelte +178 -205
  195. package/dist/ui/Button.svelte.d.ts +19 -2
  196. package/dist/ui/ButtonVariant.d.ts +15 -1
  197. package/dist/ui/ContextMenu.svelte +146 -0
  198. package/dist/ui/ContextMenu.svelte.d.ts +37 -0
  199. package/dist/ui/ContextMenuList.svelte +188 -0
  200. package/dist/ui/ContextMenuList.svelte.d.ts +12 -0
  201. package/dist/ui/Dialog.svelte +183 -111
  202. package/dist/ui/Dialog.svelte.d.ts +21 -4
  203. package/dist/ui/Drawer.svelte +237 -184
  204. package/dist/ui/Drawer.svelte.d.ts +20 -2
  205. package/dist/ui/Dropdown.svelte +24 -14
  206. package/dist/ui/Dropdown.svelte.d.ts +11 -2
  207. package/dist/ui/Dropzone.svelte +159 -57
  208. package/dist/ui/Dropzone.svelte.d.ts +29 -2
  209. package/dist/ui/Link.svelte +12 -4
  210. package/dist/ui/Link.svelte.d.ts +8 -2
  211. package/dist/ui/Loader.svelte +23 -18
  212. package/dist/ui/Loader.svelte.d.ts +5 -2
  213. package/dist/ui/Logo.svelte +37 -0
  214. package/dist/ui/Logo.svelte.d.ts +16 -0
  215. package/dist/ui/MultiSortable.svelte +287 -0
  216. package/dist/ui/MultiSortable.svelte.d.ts +50 -0
  217. package/dist/ui/Pagination.svelte +15 -9
  218. package/dist/ui/Pagination.svelte.d.ts +6 -2
  219. package/dist/ui/Popover.svelte +43 -65
  220. package/dist/ui/Popover.svelte.d.ts +14 -5
  221. package/dist/ui/ProgressBar.svelte +28 -30
  222. package/dist/ui/ProgressBarVariant.d.ts +7 -1
  223. package/dist/ui/SegmentedControl.svelte +0 -0
  224. package/dist/ui/SegmentedControl.svelte.d.ts +26 -0
  225. package/dist/ui/Sortable.svelte +163 -0
  226. package/dist/ui/Sortable.svelte.d.ts +47 -0
  227. package/dist/ui/Table.svelte +383 -80
  228. package/dist/ui/Table.svelte.d.ts +43 -2
  229. package/dist/ui/Tabs.svelte +22 -18
  230. package/dist/ui/Tabs.svelte.d.ts +6 -2
  231. package/dist/ui/ThemeSwitcher.svelte +26 -7
  232. package/dist/ui/ThemeSwitcher.svelte.d.ts +4 -2
  233. package/dist/ui/Tooltip.svelte +312 -180
  234. package/dist/ui/Tooltip.svelte.d.ts +4 -3
  235. package/dist/uiTheme.svelte.d.ts +86 -0
  236. package/dist/uiTheme.svelte.js +214 -0
  237. package/dist/util/DateFunctions.js +1 -1
  238. package/dist/util/DragDrop.d.ts +50 -0
  239. package/dist/util/DragDrop.js +154 -0
  240. package/dist/util/NavigateTo.js +2 -2
  241. package/dist/util/dayjs.d.ts +4 -0
  242. package/dist/util/dayjs.js +15 -0
  243. package/package.json +66 -26
  244. package/dist/display/Alert.svelte +0 -179
  245. package/dist/display/Alert.svelte.d.ts +0 -13
  246. package/dist/form/FileInput.svelte +0 -235
  247. package/dist/form/FileInput.svelte.d.ts +0 -23
  248. package/dist/form/PasswordInput.svelte +0 -253
  249. package/dist/form/PasswordInput.svelte.d.ts +0 -34
  250. package/dist/form/Rating.svelte +0 -235
  251. package/dist/form/Rating.svelte.d.ts +0 -21
  252. package/dist/styles/components.css +0 -199
  253. package/dist/styles/dark.css +0 -146
  254. package/dist/styles/index.css +0 -116
  255. package/dist/styles/reset.css +0 -110
  256. package/dist/styles/semantic.css +0 -86
  257. package/dist/styles/tokens.css +0 -203
  258. package/dist/styles/utilities.css +0 -523
  259. package/dist/ui/Breadcrumbs.svelte +0 -131
  260. package/dist/ui/Breadcrumbs.svelte.d.ts +0 -16
  261. package/dist/ui/LoadingOverlay.svelte +0 -53
  262. package/dist/ui/LoadingOverlay.svelte.d.ts +0 -11
  263. package/dist/ui/Progress.svelte +0 -191
  264. package/dist/ui/Progress.svelte.d.ts +0 -15
  265. package/dist/ui/RingProgress.svelte +0 -141
  266. package/dist/ui/RingProgress.svelte.d.ts +0 -18
  267. package/dist/ui/Skeleton.svelte +0 -85
  268. package/dist/ui/Skeleton.svelte.d.ts +0 -12
  269. package/dist/ui/Stepper.svelte +0 -355
  270. package/dist/ui/Stepper.svelte.d.ts +0 -24
  271. package/dist/ui/Timeline.svelte +0 -225
  272. package/dist/ui/Timeline.svelte.d.ts +0 -23
  273. /package/dist/{actions → util}/ClickOutside.d.ts +0 -0
  274. /package/dist/{actions → util}/ClickOutside.js +0 -0
  275. /package/dist/{transitions → util}/Transitions.d.ts +0 -0
  276. /package/dist/{transitions → util}/Transitions.js +0 -0
@@ -1,102 +1,82 @@
1
1
  <script lang="ts">
2
- import type { LinkNavbarItem } from "../models/NavbarItem.js";
3
- import type { SidenavSection } from "./Sidenav.svelte";
2
+ import type { NavbarItem } from '../models/NavbarItem.js';
4
3
  import {
5
- Link,
6
4
  ThemeSwitcher,
7
5
  ActionIcon,
8
- Drawer,
9
6
  iconHamburger,
10
7
  type Hyperlink,
11
- } from "../index.js";
12
- import { themeState } from "../theme.svelte.js";
13
- import type { Snippet } from "svelte";
8
+ viewportState
9
+ } from '../index.js';
10
+ import NavbarItemView from './NavbarItemView.svelte';
11
+ import Link from '../ui/Link.svelte';
12
+ import Logo from '../ui/Logo.svelte';
13
+ import type { Snippet } from 'svelte';
14
14
 
15
- interface Props {
16
- drawerHeader?: string | undefined;
15
+ /** `midnight` is a legacy alias for `primary`. */
16
+ export type NavbarVariant = 'default' | 'primary' | 'midnight';
17
+
18
+ export interface NavbarProps {
19
+ /** Visual variant. `primary` uses the primary brand colour as the background across all themes */
20
+ variant?: NavbarVariant;
21
+ /** App navigation link displayed as a header */
17
22
  appNav?: Hyperlink;
18
- items?: LinkNavbarItem[];
19
- secondaryItems?: LinkNavbarItem[];
23
+ /** Primary navigation items. Items with `subItems` fold out a vertical sub-list; items with `iconSvg` show a leading icon */
24
+ items?: NavbarItem[];
25
+ /** Secondary navigation items (right side) */
26
+ secondaryItems?: NavbarItem[];
27
+ /** Hide the logo */
28
+ noLogo?: boolean;
29
+ /** Custom URL for the logo link */
30
+ logoHref?: string;
31
+ /** Additional CSS classes */
20
32
  class?: string;
33
+ /** Constrain navbar width to container */
21
34
  inContainer?: boolean;
35
+ /** Custom content for the left section */
36
+ leftSection?: Snippet;
37
+ /** Custom content for the middle section */
22
38
  middleSection?: Snippet;
39
+ /** Custom content for the right section */
23
40
  rightSection?: Snippet;
24
- /** Icons displayed to the left of the ThemeSwitcher, visible even when collapsed on mobile */
25
- iconSection?: Snippet;
26
- /** Enable responsive collapse to burger menu on small screens (default: true) */
27
- responsive?: boolean;
28
- /** Breakpoint in pixels at which the navbar collapses (default: 768) */
29
- responsiveBreakpoint?: number;
30
- // Drawer button options
41
+ /** Show mobile drawer toggle button */
31
42
  showDrawerButton?: boolean;
32
- drawerButtonPosition?: "left" | "right";
43
+ /** Position of the drawer toggle button */
44
+ drawerButtonPosition?: 'left' | 'right';
45
+ /** Custom icon for the drawer toggle button */
33
46
  drawerButtonIcon?: string;
47
+ /** Callback when drawer toggle is clicked */
34
48
  onDrawerButtonClick?: () => void;
35
49
  }
36
50
 
37
51
  let {
38
- drawerHeader = undefined,
52
+ variant = 'default',
39
53
  appNav = undefined,
40
54
  items = [],
41
55
  secondaryItems = [],
42
- class: className = "",
56
+ noLogo = false,
57
+ logoHref = undefined,
58
+ class: className = '',
43
59
  inContainer = false,
60
+ leftSection = undefined,
44
61
  middleSection = undefined,
45
62
  rightSection = undefined,
46
- iconSection = undefined,
47
- responsive = true,
48
- responsiveBreakpoint = 768,
49
63
  // Drawer button options
50
64
  showDrawerButton = false,
51
- drawerButtonPosition = "right",
65
+ drawerButtonPosition = 'right',
52
66
  drawerButtonIcon = iconHamburger,
53
- onDrawerButtonClick = undefined,
54
- }: Props = $props();
55
-
56
- let drawerOpen = $state(false);
57
- let windowWidth = $state(
58
- typeof window !== "undefined" ? window.innerWidth : 1024,
59
- );
60
- const isCollapsed = $derived(
61
- responsive && windowWidth <= responsiveBreakpoint,
62
- );
63
-
64
- const drawerSections = $derived.by((): SidenavSection[] => {
65
- const sections: SidenavSection[] = [];
66
- if (items.length > 0) {
67
- sections.push({
68
- items: items.map((item) => ({
69
- label: item.label,
70
- href: item.href,
71
- iconSvg: item.iconSvg,
72
- })),
73
- });
74
- }
75
- if (secondaryItems.length > 0) {
76
- sections.push({
77
- items: secondaryItems.map((item) => ({
78
- label: item.label,
79
- href: item.href,
80
- iconSvg: item.iconSvg,
81
- })),
82
- });
83
- }
84
- return sections;
85
- });
67
+ onDrawerButtonClick = undefined
68
+ }: NavbarProps = $props();
86
69
 
87
- function handleBurgerClick() {
88
- drawerOpen = true;
89
- }
70
+ const isPrimary = $derived(variant === 'primary' || variant === 'midnight');
90
71
  </script>
91
72
 
92
- <svelte:window onresize={() => (windowWidth = window.innerWidth)} />
93
-
94
- <header>
73
+ <header class={isPrimary ? 'primary' : ''}>
95
74
  <div class="inner-navbar {className} {inContainer ? 'container' : ''}">
96
- {#if showDrawerButton && drawerButtonPosition === "left"}
75
+ {@render leftSection?.()}
76
+ {#if showDrawerButton && drawerButtonPosition === 'left'}
97
77
  <ActionIcon
98
78
  svg={drawerButtonIcon}
99
- variant="secondary-subtle"
79
+ variant={isPrimary ? 'accent-subtle' : 'secondary-subtle'}
100
80
  size="1.25rem"
101
81
  onclick={onDrawerButtonClick}
102
82
  class="drawer-btn drawer-btn-left"
@@ -108,54 +88,52 @@
108
88
  </div>
109
89
  {/if}
110
90
 
111
- {#if !isCollapsed}
91
+ {#if items.length > 0}
112
92
  <div class="primary links-container">
113
93
  {#each items as item}
114
- <Link href={item.href}>{item.label}</Link>
94
+ <NavbarItemView {item} />
115
95
  {/each}
116
96
  </div>
117
97
  {/if}
118
98
 
119
- <div class="middle">
120
- {@render middleSection?.()}
121
- </div>
122
-
123
- {#if !isCollapsed}
99
+ {#if middleSection}
100
+ <div class="middle">
101
+ {@render middleSection()}
102
+ </div>
103
+ {/if}
104
+ <!-- <ActionIcon
105
+ class="hamburger"
106
+ variant={$isDarkMode ? 'auto-subtle' : 'primary'}
107
+ onclick={toggleDrawer}
108
+ svg={iconHamburger}
109
+ /> -->
110
+ {#if secondaryItems.length > 0}
124
111
  <div class="secondary links-container">
125
112
  {#each secondaryItems as item}
126
- {#if item.href.indexOf("/") === 0}
127
- <Link href={item.href}>{item.label}</Link>
128
- {:else}
129
- <a href={item.href}>{item.label}</a>
130
- {/if}
113
+ <NavbarItemView {item} />
131
114
  {/each}
132
115
  </div>
133
- {@render rightSection?.()}
134
116
  {/if}
135
- <div class="icon-section">
136
- {#if iconSection}
137
- {@render iconSection()}
117
+ {#if rightSection}
118
+ <div class="right">
119
+ {@render rightSection()}
120
+ </div>
121
+ {/if}
122
+ <ThemeSwitcher
123
+ darkVariant="accent-subtle"
124
+ lightVariant={isPrimary ? 'accent-subtle' : 'primary-subtle'}
125
+ />
126
+ {#if !viewportState.isMobile && !noLogo}
127
+ {#if logoHref}
128
+ <Logo href={logoHref} fill={isPrimary ? 'white' : undefined} />
129
+ {:else}
130
+ <Logo fill={isPrimary ? 'white' : undefined} />
138
131
  {/if}
139
- <ThemeSwitcher
140
- darkVariant="secondary-subtle"
141
- lightVariant="primary-subtle"
142
- />
143
- </div>
144
- {#if isCollapsed}
145
- <ActionIcon
146
- svg={iconHamburger}
147
- variant={themeState.isDarkMode
148
- ? "secondary-subtle"
149
- : "primary-subtle"}
150
- size="1.25rem"
151
- onclick={handleBurgerClick}
152
- class="responsive-burger"
153
- />
154
132
  {/if}
155
- {#if showDrawerButton && drawerButtonPosition === "right"}
133
+ {#if showDrawerButton && drawerButtonPosition === 'right'}
156
134
  <ActionIcon
157
135
  svg={drawerButtonIcon}
158
- variant="secondary-subtle"
136
+ variant={isPrimary ? 'accent-subtle' : 'secondary-subtle'}
159
137
  size="1.25rem"
160
138
  onclick={onDrawerButtonClick}
161
139
  class="drawer-btn drawer-btn-right"
@@ -164,55 +142,116 @@
164
142
  </div>
165
143
  </header>
166
144
 
167
- {#if responsive}
168
- <Drawer
169
- bind:open={drawerOpen}
170
- title={drawerHeader ?? appNav?.text ?? ""}
171
- sections={drawerSections}
172
- closeForLargeScreens={true}
173
- largeScreenBreakpoint={responsiveBreakpoint}
174
- />
175
- {/if}
176
-
177
145
  <style>
178
146
  header {
179
147
  position: sticky;
180
148
  top: 0;
181
- z-index: var(--pui-z-sticky);
182
- height: 46px;
149
+ z-index: 40;
150
+ height: var(--header-height);
183
151
  display: flex;
184
- background: var(--pui-color-white);
185
- border-bottom: 1px solid var(--pui-border-default);
152
+ background: white;
153
+ border-bottom: 0.666667px solid rgb(222, 226, 230);
186
154
  }
187
155
 
188
156
  .links-container {
189
157
  display: flex;
190
- gap: var(--pui-spacing-4);
158
+ gap: 1rem;
191
159
  }
192
160
 
193
161
  :global(.dark) header {
194
- background: var(--pui-color-black);
162
+ background: black;
195
163
  border: none;
196
164
  }
197
165
 
166
+ /* Primary variant: primary brand background regardless of theme */
167
+ header.primary,
168
+ :global(.dark) header.primary {
169
+ background: var(--ui-primary);
170
+ border: none;
171
+ }
172
+
173
+ header.primary .inner-navbar {
174
+ color: white;
175
+ }
176
+
177
+ /* Top-level links/triggers: white, turning accent on hover (matches dark navbar).
178
+ Use `>` so these rules don't leak into the fold-out sub-list panels, which keep
179
+ their own (paper) colour scheme regardless of the primary variant. */
180
+ header.primary .inner-navbar .links-container > :global(a),
181
+ header.primary
182
+ .inner-navbar
183
+ .links-container
184
+ > :global(.navbar-parent)
185
+ > :global(.navbar-parent-trigger),
186
+ header.primary .inner-navbar .header-hero :global(a) {
187
+ color: white;
188
+ transition: color 200ms;
189
+ }
190
+
191
+ header.primary .inner-navbar .links-container > :global(a:hover),
192
+ header.primary
193
+ .inner-navbar
194
+ .links-container
195
+ > :global(.navbar-parent)
196
+ > :global(.navbar-parent-trigger:hover),
197
+ header.primary .inner-navbar .header-hero :global(a:hover) {
198
+ color: var(--ui-accent);
199
+ }
200
+
198
201
  .inner-navbar {
199
202
  display: flex;
200
203
  align-items: center;
201
- gap: var(--pui-spacing-4);
204
+ gap: 1rem;
202
205
 
203
206
  margin: 0 auto;
204
- padding: 0 var(--pui-spacing-4);
207
+ padding: 0 1em;
205
208
  height: 100%;
206
209
  width: 100%;
207
- color: var(--pui-color-primary);
210
+ color: var(--ui-primary);
208
211
  }
209
212
 
210
213
  .middle {
211
214
  flex-grow: 1;
212
215
  }
213
216
 
214
- .inner-navbar :global(.responsive-burger) {
215
- flex-shrink: 0;
217
+ /* Without a growing .middle, the first right-side element pushes the group to the
218
+ edge via auto margin. When .middle is present its flex-grow consumes the free
219
+ space first, so these margins resolve to 0 and have no effect. */
220
+ .secondary,
221
+ .right,
222
+ .inner-navbar > :global(.theme-switcher) {
223
+ margin-left: auto;
224
+ }
225
+
226
+ .secondary ~ .right,
227
+ .secondary ~ :global(.theme-switcher),
228
+ .right ~ :global(.theme-switcher) {
229
+ margin-left: 0;
230
+ }
231
+
232
+ .hidden-when-small {
233
+ display: none;
234
+ }
235
+
236
+ .inner-navbar :global(.hamburger) {
237
+ margin-left: auto;
238
+ }
239
+
240
+ @media (max-width: 640px) {
241
+ .hidden-when-small {
242
+ display: block;
243
+ }
244
+
245
+ .inner-navbar :global(.hamburger) {
246
+ display: none;
247
+ }
248
+ }
249
+
250
+ .top-header {
251
+ border-bottom-width: 1px;
252
+ border-bottom-style: solid;
253
+ border-color: var(--border-color);
254
+ height: 1.5rem;
216
255
  }
217
256
 
218
257
  .inner-navbar :global(.cu-icon) {
@@ -224,17 +263,10 @@
224
263
  }
225
264
 
226
265
  .inner-navbar :global(.drawer-btn-left) {
227
- margin-right: var(--pui-spacing-1);
266
+ margin-right: 0.25rem;
228
267
  }
229
268
 
230
269
  .inner-navbar :global(.drawer-btn-right) {
231
- margin-left: var(--pui-spacing-2);
232
- }
233
-
234
- .icon-section {
235
- display: flex;
236
- align-items: center;
237
- gap: var(--pui-spacing-1);
238
- flex-shrink: 0;
270
+ margin-left: 0.5rem;
239
271
  }
240
272
  </style>
@@ -1,26 +1,40 @@
1
- import type { LinkNavbarItem } from "../models/NavbarItem.js";
2
- import { type Hyperlink } from "../index.js";
3
- import type { Snippet } from "svelte";
4
- interface Props {
5
- drawerHeader?: string | undefined;
1
+ import type { NavbarItem } from '../models/NavbarItem.js';
2
+ import { type Hyperlink } from '../index.js';
3
+ import type { Snippet } from 'svelte';
4
+ /** `midnight` is a legacy alias for `primary`. */
5
+ export type NavbarVariant = 'default' | 'primary' | 'midnight';
6
+ export interface NavbarProps {
7
+ /** Visual variant. `primary` uses the primary brand colour as the background across all themes */
8
+ variant?: NavbarVariant;
9
+ /** App navigation link displayed as a header */
6
10
  appNav?: Hyperlink;
7
- items?: LinkNavbarItem[];
8
- secondaryItems?: LinkNavbarItem[];
11
+ /** Primary navigation items. Items with `subItems` fold out a vertical sub-list; items with `iconSvg` show a leading icon */
12
+ items?: NavbarItem[];
13
+ /** Secondary navigation items (right side) */
14
+ secondaryItems?: NavbarItem[];
15
+ /** Hide the logo */
16
+ noLogo?: boolean;
17
+ /** Custom URL for the logo link */
18
+ logoHref?: string;
19
+ /** Additional CSS classes */
9
20
  class?: string;
21
+ /** Constrain navbar width to container */
10
22
  inContainer?: boolean;
23
+ /** Custom content for the left section */
24
+ leftSection?: Snippet;
25
+ /** Custom content for the middle section */
11
26
  middleSection?: Snippet;
27
+ /** Custom content for the right section */
12
28
  rightSection?: Snippet;
13
- /** Icons displayed to the left of the ThemeSwitcher, visible even when collapsed on mobile */
14
- iconSection?: Snippet;
15
- /** Enable responsive collapse to burger menu on small screens (default: true) */
16
- responsive?: boolean;
17
- /** Breakpoint in pixels at which the navbar collapses (default: 768) */
18
- responsiveBreakpoint?: number;
29
+ /** Show mobile drawer toggle button */
19
30
  showDrawerButton?: boolean;
20
- drawerButtonPosition?: "left" | "right";
31
+ /** Position of the drawer toggle button */
32
+ drawerButtonPosition?: 'left' | 'right';
33
+ /** Custom icon for the drawer toggle button */
21
34
  drawerButtonIcon?: string;
35
+ /** Callback when drawer toggle is clicked */
22
36
  onDrawerButtonClick?: () => void;
23
37
  }
24
- declare const Navbar: import("svelte").Component<Props, {}, "">;
38
+ declare const Navbar: import("svelte").Component<NavbarProps, {}, "">;
25
39
  type Navbar = ReturnType<typeof Navbar>;
26
40
  export default Navbar;
@@ -1,6 +1,6 @@
1
1
  <!-- <script lang="ts">
2
- import Icon from '../icon/Icon.svelte';
3
- import Link from '../ui/Link.svelte';
2
+ import Icon from "../icon/Icon.svelte";
3
+ import Link from "../ui/Link.svelte";
4
4
  import type { NavbarItem } from "../models/NavbarItem.js";
5
5
 
6
6
  export let item: NavbarItem;
@@ -0,0 +1,182 @@
1
+ <script lang="ts">
2
+ import type { NavbarItem } from '../models/NavbarItem.js';
3
+ import Link from '../ui/Link.svelte';
4
+ import Icon from '../icon/Icon.svelte';
5
+ import { iconChevronDown, iconChevronRight } from '../icon/index.js';
6
+ import { clickOutside } from '../util/ClickOutside.js';
7
+ // Self-import enables recursive rendering of nested sub-lists (Svelte 5 replacement for svelte:self)
8
+ import Self from './NavbarItemView.svelte';
9
+
10
+ export interface NavbarItemViewProps {
11
+ /** The navigation item to render */
12
+ item: NavbarItem;
13
+ /** Nesting depth. 0 = top level (sub-list folds down), >0 = nested (flies out to the side) */
14
+ depth?: number;
15
+ }
16
+
17
+ let { item, depth = 0 }: NavbarItemViewProps = $props();
18
+
19
+ let open = $state(false);
20
+
21
+ const close = () => (open = false);
22
+ </script>
23
+
24
+ {#if 'component' in item}
25
+ {@const Component = item.component}
26
+ <Component {...item.componentProps} />
27
+ {:else if 'href' in item}
28
+ <Link href={item.href} onclick={item.onclick} class="navbar-item {item.class ?? ''}">
29
+ {#if item.iconSvg}
30
+ <Icon svg={item.iconSvg} size="1.1em" class="navbar-item-icon" />
31
+ {/if}
32
+ <span>{item.label}</span>
33
+ </Link>
34
+ {:else}
35
+ <div class="navbar-parent" use:clickOutside={close}>
36
+ <button
37
+ type="button"
38
+ class="navbar-item navbar-parent-trigger {item.class ?? ''}"
39
+ aria-expanded={open}
40
+ aria-haspopup="true"
41
+ onclick={(e) => {
42
+ item.onclick?.(e);
43
+ open = !open;
44
+ }}
45
+ >
46
+ {#if item.iconSvg}
47
+ <Icon svg={item.iconSvg} size="1.1em" class="navbar-item-icon" />
48
+ {/if}
49
+ <span>{item.label}</span>
50
+ {#if item.subItems?.length}
51
+ <Icon
52
+ svg={depth > 0 ? iconChevronRight : iconChevronDown}
53
+ size="0.85em"
54
+ class="navbar-chevron"
55
+ />
56
+ {/if}
57
+ </button>
58
+ {#if open && item.subItems?.length}
59
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
60
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
61
+ <div
62
+ class="navbar-submenu"
63
+ class:flyout={depth > 0}
64
+ style={item.submenuWidth ? `width: ${item.submenuWidth}; min-width: ${item.submenuWidth};` : ''}
65
+ onclick={(e) => {
66
+ // Close the fold-out once an actual link is chosen (but not when toggling a nested parent)
67
+ if ((e.target as HTMLElement).closest('a')) close();
68
+ }}
69
+ >
70
+ {#each item.subItems as subItem}
71
+ <Self item={subItem} depth={depth + 1} />
72
+ {/each}
73
+ </div>
74
+ {/if}
75
+ </div>
76
+ {/if}
77
+
78
+ <style>
79
+ .navbar-parent {
80
+ position: relative;
81
+ display: inline-flex;
82
+ }
83
+
84
+ /* Shared look for links and parent triggers so they line up in the navbar row */
85
+ :global(.navbar-item) {
86
+ display: inline-flex;
87
+ align-items: center;
88
+ gap: 0.4rem;
89
+ }
90
+
91
+ /* Match the global `header a` link styling so triggers and links look identical.
92
+ A <button> doesn't inherit those rules, so set the colours explicitly. */
93
+ .navbar-parent-trigger {
94
+ background: none;
95
+ border: none;
96
+ padding: 0;
97
+ margin: 0;
98
+ font: inherit;
99
+ color: var(--ui-primary);
100
+ cursor: pointer;
101
+ transition: color 200ms;
102
+ }
103
+
104
+ .navbar-parent-trigger:hover {
105
+ color: var(--ui-accent-dark);
106
+ }
107
+
108
+ :global(.dark) .navbar-parent-trigger {
109
+ color: white;
110
+ }
111
+
112
+ :global(.dark) .navbar-parent-trigger:hover {
113
+ color: var(--ui-accent);
114
+ }
115
+
116
+ :global(.navbar-item-icon) {
117
+ flex-shrink: 0;
118
+ }
119
+
120
+ :global(.navbar-chevron) {
121
+ flex-shrink: 0;
122
+ opacity: 0.7;
123
+ }
124
+
125
+ /* Fold-out vertical sub-list */
126
+ .navbar-submenu {
127
+ position: absolute;
128
+ top: 100%;
129
+ left: 0;
130
+ margin-top: 0.5rem;
131
+ display: flex;
132
+ flex-direction: column;
133
+ gap: 0.125rem;
134
+ min-width: 12rem;
135
+ background-color: var(--paper-body-bg);
136
+ border: 1px solid var(--border-color);
137
+ border-radius: 0.375rem;
138
+ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
139
+ z-index: 1000;
140
+ }
141
+
142
+ /* Nested sub-lists fly out to the side instead of downward */
143
+ .navbar-submenu.flyout {
144
+ top: 0;
145
+ left: 100%;
146
+ margin-top: 0;
147
+ margin-left: 0.25rem;
148
+ }
149
+
150
+ /* Items inside the panel always use the panel's own colour scheme,
151
+ regardless of the navbar variant (matches the Dropdown component). */
152
+ .navbar-submenu :global(.navbar-item) {
153
+ width: 100%;
154
+ padding: 0.4rem 0.6rem;
155
+ color: var(--ui-primary);
156
+ text-decoration: none;
157
+ transition: background-color 0.15s ease;
158
+ }
159
+
160
+ .navbar-submenu :global(.navbar-item:first-child) {
161
+ border-top-left-radius: 0.25rem;
162
+ border-top-right-radius: 0.25rem;
163
+ }
164
+
165
+ .navbar-submenu :global(.navbar-item:last-child) {
166
+ border-bottom-left-radius: 0.25rem;
167
+ border-bottom-right-radius: 0.25rem;
168
+ }
169
+
170
+ .navbar-submenu :global(.navbar-item:hover) {
171
+ background-color: var(--border-color);
172
+ color: var(--ui-primary);
173
+ }
174
+
175
+ :global(.dark) .navbar-submenu :global(.navbar-item) {
176
+ color: var(--ui-accent);
177
+ }
178
+
179
+ :global(.dark) .navbar-submenu :global(.navbar-item:hover) {
180
+ color: var(--ui-accent);
181
+ }
182
+ </style>
@@ -0,0 +1,10 @@
1
+ import type { NavbarItem } from '../models/NavbarItem.js';
2
+ export interface NavbarItemViewProps {
3
+ /** The navigation item to render */
4
+ item: NavbarItem;
5
+ /** Nesting depth. 0 = top level (sub-list folds down), >0 = nested (flies out to the side) */
6
+ depth?: number;
7
+ }
8
+ declare const NavbarItemView: import("svelte").Component<NavbarItemViewProps, {}, "">;
9
+ type NavbarItemView = ReturnType<typeof NavbarItemView>;
10
+ export default NavbarItemView;