@flikk/ui 1.0.0-beta.26 → 1.0.0-beta.27

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 (131) hide show
  1. package/dist/components/ai/PromptInput/PromptInput.js +3 -0
  2. package/dist/components/ai/PromptInput/VoiceRecorder.js +3 -0
  3. package/dist/components/core/Button/Button.theme.js +1 -1
  4. package/dist/components/core/Calendar/Calendar.theme.js +1 -1
  5. package/dist/components/core/CommandPalette/CommandItem.js +4 -5
  6. package/dist/components/core/CommandPalette/CommandPalette.js +1 -1
  7. package/dist/components/core/CommandPalette/CommandPalette.theme.js +11 -13
  8. package/dist/components/core/CommandPalette/CommandPalette.types.d.ts +0 -2
  9. package/dist/components/core/ContextMenu/ContextMenu.theme.js +13 -14
  10. package/dist/components/core/DotSeparator/DotSeparator.d.ts +3 -0
  11. package/dist/components/core/DotSeparator/DotSeparator.js +19 -0
  12. package/dist/components/core/DotSeparator/DotSeparator.theme.d.ts +2 -0
  13. package/dist/components/core/DotSeparator/DotSeparator.theme.js +10 -0
  14. package/dist/components/core/DotSeparator/DotSeparator.types.d.ts +25 -0
  15. package/dist/components/core/DotSeparator/index.d.ts +3 -0
  16. package/dist/components/core/Dropdown/Dropdown.theme.js +2 -3
  17. package/dist/components/core/Dropdown/DropdownItem.js +1 -1
  18. package/dist/components/core/Dropdown/DropdownMenu.js +1 -1
  19. package/dist/components/core/MenuItem/MenuItem.js +5 -2
  20. package/dist/components/core/MenuItem/MenuItem.theme.d.ts +6 -0
  21. package/dist/components/core/MenuItem/MenuItem.theme.js +19 -16
  22. package/dist/components/core/MenuItem/MenuItem.types.d.ts +2 -0
  23. package/dist/components/core/NavItem/NavItem.js +20 -4
  24. package/dist/components/core/NavItem/NavItem.theme.js +13 -2
  25. package/dist/components/core/Popover/Popover.types.d.ts +6 -2
  26. package/dist/components/core/Popover/PopoverBody.js +10 -3
  27. package/dist/components/core/Segmented/Segmented.theme.js +1 -1
  28. package/dist/components/core/Sidebar/Sidebar.d.ts +2 -0
  29. package/dist/components/core/Sidebar/Sidebar.js +15 -7
  30. package/dist/components/core/Sidebar/Sidebar.types.d.ts +92 -4
  31. package/dist/components/core/Sidebar/SidebarCard.d.ts +25 -0
  32. package/dist/components/core/Sidebar/SidebarCard.js +68 -0
  33. package/dist/components/core/Sidebar/SidebarCard.theme.d.ts +8 -0
  34. package/dist/components/core/Sidebar/SidebarCard.theme.js +18 -0
  35. package/dist/components/core/Sidebar/SidebarContent.js +5 -1
  36. package/dist/components/core/Sidebar/SidebarContext.js +1 -1
  37. package/dist/components/core/Sidebar/SidebarHeader.js +10 -2
  38. package/dist/components/core/Sidebar/SidebarLogo.js +38 -3
  39. package/dist/components/core/Sidebar/SidebarSearch.d.ts +22 -0
  40. package/dist/components/core/Sidebar/SidebarSearch.js +135 -0
  41. package/dist/components/core/Sidebar/SidebarToggle.js +1 -1
  42. package/dist/components/core/Sidebar/SidebarUserProfile.js +2 -2
  43. package/dist/components/core/Sidebar/index.d.ts +3 -1
  44. package/dist/components/core/Tag/Tag.js +29 -5
  45. package/dist/components/core/Tag/Tag.theme.js +13 -8
  46. package/dist/components/core/Tag/Tag.types.d.ts +7 -0
  47. package/dist/components/core/Tooltip/Tooltip.js +1 -1
  48. package/dist/components/core/Tooltip/Tooltip.theme.js +1 -2
  49. package/dist/components/core/index.d.ts +1 -0
  50. package/dist/components/core/index.js +4 -0
  51. package/dist/components/data-display/GanttChart/GanttChart.d.ts +1 -1
  52. package/dist/components/data-display/GanttChart/GanttChart.js +31 -4
  53. package/dist/components/data-display/GanttChart/GanttChart.theme.js +19 -17
  54. package/dist/components/data-display/GanttChart/GanttChart.types.d.ts +19 -0
  55. package/dist/components/data-display/GanttChart/GanttChart.utils.js +1 -1
  56. package/dist/components/data-display/GanttChart/GanttChartPanel.d.ts +1 -1
  57. package/dist/components/data-display/GanttChart/GanttChartPanel.js +3 -3
  58. package/dist/components/data-display/GanttChart/GanttDependencyArrows.js +7 -4
  59. package/dist/components/data-display/GanttChart/GanttMilestone.js +5 -5
  60. package/dist/components/data-display/GanttChart/GanttTablePanel.js +1 -1
  61. package/dist/components/data-display/GanttChart/GanttTableTaskRow.js +2 -2
  62. package/dist/components/data-display/GanttChart/GanttTaskBar.js +37 -16
  63. package/dist/components/data-display/GanttChart/GanttTimelineGrid.js +2 -1
  64. package/dist/components/data-display/GanttChart/GanttTimelineHeader.js +35 -11
  65. package/dist/components/data-display/GanttChart/GanttToolbar.js +2 -2
  66. package/dist/components/data-display/GanttChart/hooks/useGanttDrag.js +3 -2
  67. package/dist/components/data-display/GanttChart/index.d.ts +1 -1
  68. package/dist/components/data-display/Table/Table.theme.js +3 -5
  69. package/dist/components/effects/Aurora/Aurora.d.ts +6 -17
  70. package/dist/components/effects/Aurora/Aurora.js +297 -131
  71. package/dist/components/effects/Aurora/Aurora.types.d.ts +6 -0
  72. package/dist/components/forms/Combobox/Combobox.js +1 -1
  73. package/dist/components/forms/Combobox/Combobox.theme.js +2 -4
  74. package/dist/components/forms/CronInput/CronInput.js +1 -1
  75. package/dist/components/forms/CronInput/CronInput.theme.js +14 -23
  76. package/dist/components/forms/DatePicker/DatePicker.theme.js +11 -18
  77. package/dist/components/forms/DatePicker/DatePickerTrigger.js +1 -1
  78. package/dist/components/forms/DateRangePicker/DateRangePicker.theme.js +6 -13
  79. package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +1 -1
  80. package/dist/components/forms/FileUpload/FileUpload.animations.d.ts +29 -0
  81. package/dist/components/forms/FileUpload/FileUpload.animations.js +19 -0
  82. package/dist/components/forms/FileUpload/FileUpload.js +87 -48
  83. package/dist/components/forms/FileUpload/FileUpload.theme.d.ts +2 -10
  84. package/dist/components/forms/FileUpload/FileUpload.theme.js +16 -30
  85. package/dist/components/forms/FileUpload/FileUpload.types.d.ts +26 -10
  86. package/dist/components/forms/Input/Input.theme.js +13 -10
  87. package/dist/components/forms/InputCounter/InputCounter.theme.js +1 -1
  88. package/dist/components/forms/Mention/Mention.js +152 -57
  89. package/dist/components/forms/Mention/Mention.theme.js +16 -23
  90. package/dist/components/forms/Mention/Mention.types.d.ts +12 -12
  91. package/dist/components/forms/Mention/Mention.utils.js +32 -4
  92. package/dist/components/forms/RichTextEditor/RichTextEditor.js +3 -3
  93. package/dist/components/forms/RichTextEditor/RichTextEditor.theme.js +5 -5
  94. package/dist/components/forms/Select/Select.js +2 -2
  95. package/dist/components/forms/Select/Select.theme.js +3 -3
  96. package/dist/components/forms/TimePicker/TimePickerContent.js +3 -0
  97. package/dist/components/forms/TimePicker/TimePickerTrigger.js +1 -1
  98. package/dist/components/forms/forms.theme.js +21 -16
  99. package/dist/components/forms/index.js +3 -0
  100. package/dist/components/layout/AppShell/AppShell.d.ts +10 -0
  101. package/dist/components/layout/AppShell/AppShell.js +84 -0
  102. package/dist/components/layout/AppShell/AppShell.theme.d.ts +3 -0
  103. package/dist/components/layout/AppShell/AppShell.theme.js +42 -0
  104. package/dist/components/layout/AppShell/AppShell.types.d.ts +127 -0
  105. package/dist/components/layout/AppShell/AppShellContext.d.ts +14 -0
  106. package/dist/components/layout/AppShell/AppShellContext.js +19 -0
  107. package/dist/components/layout/AppShell/AppShellFooter.d.ts +3 -0
  108. package/dist/components/layout/AppShell/AppShellFooter.js +12 -0
  109. package/dist/components/layout/AppShell/AppShellHeader.d.ts +3 -0
  110. package/dist/components/layout/AppShell/AppShellHeader.js +12 -0
  111. package/dist/components/layout/AppShell/AppShellMain.d.ts +3 -0
  112. package/dist/components/layout/AppShell/AppShellMain.js +19 -0
  113. package/dist/components/layout/AppShell/AppShellRightPanel.d.ts +3 -0
  114. package/dist/components/layout/AppShell/AppShellRightPanel.js +16 -0
  115. package/dist/components/layout/AppShell/AppShellSidebar.d.ts +3 -0
  116. package/dist/components/layout/AppShell/AppShellSidebar.js +16 -0
  117. package/dist/components/layout/AppShell/AppShellTopbar.d.ts +3 -0
  118. package/dist/components/layout/AppShell/AppShellTopbar.js +12 -0
  119. package/dist/components/layout/AppShell/index.d.ts +3 -0
  120. package/dist/components/layout/FormLayout/FormLayout.js +3 -0
  121. package/dist/components/layout/index.d.ts +1 -0
  122. package/dist/components/layout/index.js +2 -0
  123. package/dist/hooks/useSelectPortal.d.ts +10 -2
  124. package/dist/hooks/useSelectPortal.js +45 -24
  125. package/dist/index.js +6 -0
  126. package/dist/registry.json +10021 -0
  127. package/dist/styles.css +1 -1
  128. package/dist/utils/dateUtils.js +11 -1
  129. package/package.json +4 -2
  130. package/src/global.scss +29 -8
  131. package/src/styles/theme.css +51 -12
@@ -71,26 +71,21 @@ export interface MentionTheme {
71
71
  inputGroupStyle: string;
72
72
  /** JS-driven focus ring style */
73
73
  inputGroupFocusStyle: string;
74
+ /** Invalid state style (inset box-shadow + danger fill) */
75
+ invalidStyle: string;
76
+ /** Invalid + focused style (danger inset shadow + ring glow) */
77
+ invalidFocusStyle: string;
74
78
  /** Base editable div style */
75
79
  editableStyle: string;
76
80
  /** Size variants for the editable div */
77
81
  sizes: Record<MentionSize, string>;
78
- /** Inline mention Tag chip style */
79
- mentionTagStyle: string;
80
82
  /** Dropdown container style */
81
83
  dropdownStyle: string;
82
- /** Individual suggestion item style */
84
+ /** Suggestion row style — used only by the custom `renderSuggestion` path
85
+ * (default rows render via the shared MenuItem primitive). */
83
86
  suggestionStyle: string;
84
- /** Highlighted (keyboard-focused) suggestion style */
87
+ /** Highlighted (keyboard-focused) suggestion style — custom renderSuggestion path */
85
88
  suggestionHighlightedStyle: string;
86
- /** Avatar style inside a suggestion */
87
- suggestionAvatarStyle: string;
88
- /** Avatar fallback (initials) style */
89
- suggestionAvatarFallbackStyle: string;
90
- /** Suggestion label text style */
91
- suggestionLabelStyle: string;
92
- /** Suggestion description text style */
93
- suggestionDescriptionStyle: string;
94
89
  /** Empty state message style */
95
90
  emptyMessageStyle: string;
96
91
  /** Loading state style */
@@ -153,6 +148,11 @@ export interface MentionProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
153
148
  mentionTagSize?: TagSize;
154
149
  /** Additional className for inline mention Tag chips */
155
150
  mentionTagClassName?: string;
151
+ /**
152
+ * Show a remove (×) button on each inline mention chip so it can be deleted
153
+ * by click as well as by keyboard. Defaults to `true`.
154
+ */
155
+ mentionTagRemovable?: boolean;
156
156
  /** Number of visible text rows (controls min-height) */
157
157
  rows?: number;
158
158
  /** Label rendered above the mention input */
@@ -1,5 +1,23 @@
1
1
  // Data attribute used to identify mention nodes in the DOM
2
2
  const MENTION_ATTR = "data-mention-id";
3
+ /**
4
+ * True when `node` lives inside a mention chip (its avatar/label text nodes),
5
+ * as opposed to being the mention element itself. A TreeWalker descends into a
6
+ * FILTER_ACCEPTed mention element, so without rejecting these inner nodes the
7
+ * offset walkers would count a chip's inner text and land the caret inside it
8
+ * (chips are contentEditable=false). Stops at `container` (the walker root).
9
+ */
10
+ const isInsideMention = (node, container) => {
11
+ let parent = node.parentNode;
12
+ while (parent && parent !== container) {
13
+ if (parent.nodeType === Node.ELEMENT_NODE &&
14
+ parent.hasAttribute(MENTION_ATTR)) {
15
+ return true;
16
+ }
17
+ parent = parent.parentNode;
18
+ }
19
+ return false;
20
+ };
3
21
  /**
4
22
  * Serialize segments to a plain text string.
5
23
  * Mentions become `trigger + label` (e.g. "@Sarah Wilson").
@@ -111,12 +129,17 @@ const getPlainTextOffset = (container) => {
111
129
  let offset = 0;
112
130
  const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, {
113
131
  acceptNode: (node) => {
114
- if (node.nodeType === Node.TEXT_NODE)
115
- return NodeFilter.FILTER_ACCEPT;
132
+ // Mention element: count it atomically (its inner nodes are rejected below)
116
133
  if (node.nodeType === Node.ELEMENT_NODE &&
117
134
  node.hasAttribute(MENTION_ATTR)) {
118
135
  return NodeFilter.FILTER_ACCEPT;
119
136
  }
137
+ // Reject the chip's inner avatar/label nodes so the walker never
138
+ // descends into a mention or counts its inner text twice.
139
+ if (isInsideMention(node, container))
140
+ return NodeFilter.FILTER_REJECT;
141
+ if (node.nodeType === Node.TEXT_NODE)
142
+ return NodeFilter.FILTER_ACCEPT;
120
143
  // Skip non-mention element nodes but traverse their children
121
144
  return NodeFilter.FILTER_SKIP;
122
145
  },
@@ -234,12 +257,17 @@ const setCaretAtOffset = (container, targetOffset) => {
234
257
  let remaining = targetOffset;
235
258
  const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, {
236
259
  acceptNode: (node) => {
237
- if (node.nodeType === Node.TEXT_NODE)
238
- return NodeFilter.FILTER_ACCEPT;
260
+ // Mention element: count it atomically (its inner nodes are rejected below)
239
261
  if (node.nodeType === Node.ELEMENT_NODE &&
240
262
  node.hasAttribute(MENTION_ATTR)) {
241
263
  return NodeFilter.FILTER_ACCEPT;
242
264
  }
265
+ // Reject the chip's inner avatar/label nodes so the caret is never
266
+ // placed inside a mention (chips are contentEditable=false).
267
+ if (isInsideMention(node, container))
268
+ return NodeFilter.FILTER_REJECT;
269
+ if (node.nodeType === Node.TEXT_NODE)
270
+ return NodeFilter.FILTER_ACCEPT;
243
271
  return NodeFilter.FILTER_SKIP;
244
272
  },
245
273
  });
@@ -1437,11 +1437,11 @@ const RichTextEditor = React__default.forwardRef(({ size = "md", state = "defaul
1437
1437
  : false;
1438
1438
  switch (tool) {
1439
1439
  case "bold":
1440
- return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", onMouseDown: handleMouseDown, onClick: handleBold, disabled: isDisabled, "aria-label": "Bold", "aria-pressed": isActive ? "true" : "false", children: jsx(BoldIcon, { className: "w-4 h-4" }) }, toolKey));
1440
+ return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", onMouseDown: handleMouseDown, onClick: handleBold, disabled: isDisabled, "aria-label": "Bold", "aria-pressed": isActive ? "true" : "false", children: jsx(BoldIcon, { className: "size-4" }) }, toolKey));
1441
1441
  case "italic":
1442
- return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", onMouseDown: handleMouseDown, onClick: handleItalic, disabled: isDisabled, "aria-label": "Italic", "aria-pressed": isActive ? "true" : "false", children: jsx(ItalicIcon, { className: "w-4 h-4" }) }, toolKey));
1442
+ return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", onMouseDown: handleMouseDown, onClick: handleItalic, disabled: isDisabled, "aria-label": "Italic", "aria-pressed": isActive ? "true" : "false", children: jsx(ItalicIcon, { className: "size-4" }) }, toolKey));
1443
1443
  case "underline":
1444
- return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", onMouseDown: handleMouseDown, onClick: handleUnderline, disabled: isDisabled, "aria-label": "Underline", "aria-pressed": isActive ? "true" : "false", children: jsx(UnderlineIcon, { className: "w-4 h-4" }) }, toolKey));
1444
+ return (jsx(Button, { size: "sm", color: "neutral", variant: "soft", iconOnly: true, className: cn(themeStyles.toolbarButtonStyle), "data-state": isActive ? "active" : "inactive", onMouseDown: handleMouseDown, onClick: handleUnderline, disabled: isDisabled, "aria-label": "Underline", "aria-pressed": isActive ? "true" : "false", children: jsx(UnderlineIcon, { className: "size-4" }) }, toolKey));
1445
1445
  case "fontFamily": {
1446
1446
  // The `fontFamily` tool is opt-in via toolbar config, but
1447
1447
  // `fontFamilies` is also a public prop — if a consumer passes an
@@ -97,16 +97,16 @@ const richTextEditorTheme = {
97
97
  // `rounded-t-[var(--form-radius)]` matches the container's radius so the
98
98
  // toolbar's own bg/backdrop-blur respects the top corners — prevents the
99
99
  // 1px bleed past the parent's `overflow-hidden` clip in Safari/Chromium.
100
- toolbarStyle: "flex items-center gap-1 p-1 rounded-t-[var(--form-radius)] border-b border-[var(--color-border)] dark:bg-[var(--color-background-secondary)]",
100
+ toolbarStyle: "flex items-center m-0.5 gap-0.5 p-0.5 rounded-[var(--form-radius)] dark:bg-[var(--color-surface)]/0",
101
101
  // Toolbar styling (floating variant — selection-anchored)
102
- floatingToolbarStyle: "flex items-center gap-1 p-1 rounded-xl border border-[var(--color-border)] bg-white/90 backdrop-blur-sm shadow-real-xl overflow-hidden dark:bg-[var(--color-background-secondary)]/80",
102
+ floatingToolbarStyle: "flex items-center gap-1 p-1 rounded-xl border border-[var(--color-border)] bg-[var(--color-surface-overlay)]/70 backdrop-blur-sm shadow-real-xl overflow-hidden",
103
103
  // Toolbar button — single source of truth via data-[state=active]
104
104
  // (aria-pressed remains as proper ARIA on toggle buttons, but styling is decoupled)
105
- toolbarButtonStyle: "inline-flex items-center justify-center size-8 rounded-[calc(var(--radius-base)*0.85)] border border-transparent bg-transparent text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-background-secondary)] transition-colors duration-300 disabled:opacity-50 disabled:cursor-not-allowed data-[state=active]:bg-[var(--color-background-secondary)] data-[state=active]:text-[var(--color-text-primary)] data-[state=active]:border-[var(--color-border)] data-[state=active]:shadow-inner",
105
+ toolbarButtonStyle: "inline-flex items-center justify-center rounded-[calc(var(--radius-base)*0.85)] border border-transparent bg-transparent text-[var(--color-text-secondary)] hover:text-[var(--color-text-primary)] hover:bg-[var(--color-background-secondary)] transition-colors duration-300 disabled:opacity-50 disabled:cursor-not-allowed data-[state=active]:bg-[var(--color-background-secondary)] data-[state=active]:text-[var(--color-text-primary)] data-[state=active]:border-[var(--color-border)] data-[state=active]:shadow-inner",
106
106
  // Dropdown surface (visual only — positioning handled at use site via portal)
107
- dropdownStyle: "min-w-[120px] max-h-[18rem] overflow-y-auto py-1 bg-white/90 backdrop-blur-md rounded-[var(--form-radius)] shadow-xl ring-1 ring-[var(--color-border)] focus:outline-none",
107
+ dropdownStyle: "min-w-[120px] max-h-[18rem] overflow-y-auto py-1 bg-[var(--color-surface-overlay)]/70 backdrop-blur-md rounded-[var(--form-radius)] shadow-xl ring-1 ring-[var(--color-border)] focus:outline-none",
108
108
  // Dropdown item — uses data-[active=true] for selected state
109
- dropdownItemStyle: "block w-full px-3 py-2 text-left text-sm text-[var(--color-text-primary)] hover:bg-[var(--color-surface-hover)] transition-colors duration-150 disabled:opacity-50 disabled:cursor-not-allowed data-[active=true]:bg-[var(--color-primary-50)] data-[active=true]:text-[var(--color-primary-900)]",
109
+ dropdownItemStyle: "block w-full px-3 py-2 text-left text-sm text-[var(--color-text-primary)] hover:bg-[var(--color-surface-hover)] transition-colors duration-150 disabled:opacity-50 disabled:cursor-not-allowed data-[active=true]:bg-[var(--color-primary-50)] data-[active=true]:text-[var(--color-primary-900)] data-[active=true]:dark:bg-[var(--color-primary-400)]/10 data-[active=true]:dark:text-[var(--color-primary-400)]",
110
110
  // Separator between toolbar sections
111
111
  separatorStyle: "w-px h-6 bg-[var(--color-border)] mx-1",
112
112
  // Color picker layout — column of family rows, plus optional Recent + Mono rows
@@ -96,7 +96,7 @@ const SelectButton = ({ id, disabled, isOpen, state = "default", size = "md", ic
96
96
  // Use either the themed focus state or directly apply the focus classes if the theme is not working
97
97
  const activeFocusState = isOpen
98
98
  ? focusStateStyle ||
99
- "shadow-[inset_0_0_0_2px_var(--color-primary)] ring-4 ring-[var(--color-primary)]/10"
99
+ "shadow-[inset_0_0_0_1px_var(--color-primary)] ring-4 ring-[var(--color-primary)]/10"
100
100
  : "";
101
101
  return (jsxs("div", { className: cn(buttonWrapperStyle, "flex items-stretch"), children: [contentStart && (jsx("div", { "data-slot": "content-start", className: cn(contentSlotStyle, "pr-0 border-r border-[var(--color-border)]"), children: contentStart })), jsxs("button", { ref: buttonRef, id: id, type: "button", className: cn(baseStyle, sizeStyle, stateStyle, hoverStateStyle, activeFocusState, iconStartPadding, iconEndPadding, buttonStyle, "flex-1 min-w-0", className), onClick: onClick, onFocus: onFocus, onBlur: onBlur, disabled: disabled, "aria-expanded": isOpen, "aria-haspopup": "listbox", "aria-controls": isOpen && id ? `${id}-listbox` : undefined, "aria-labelledby": ariaLabelledby, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedby, children: [iconStart && jsx("span", { className: iconStartStyle, children: iconStart }), children, iconEnd && jsx("span", { className: iconEndStyle, children: iconEnd })] }), contentEnd && (jsx("div", { "data-slot": "content-end", className: cn(contentSlotStyle, "pl-0 border-l border-[var(--color-border)]"), children: contentEnd }))] }));
102
102
  };
@@ -287,7 +287,7 @@ const SelectOptions = ({ isOpen, maxHeight = "15rem", className = "", onClose, c
287
287
  } }) })), children] })) }));
288
288
  // Use portal if enabled and client-side - wrap with dark class for dark mode support
289
289
  if (portal && isClient) {
290
- return createPortal(jsx("div", { className: isDarkMode ? "dark" : undefined, children: optionsContent }), document.body);
290
+ return createPortal(jsx("div", { "data-flikkui-portal": "", className: isDarkMode ? "dark" : undefined, children: optionsContent }), document.body);
291
291
  }
292
292
  return optionsContent;
293
293
  };
@@ -11,12 +11,12 @@ const selectTheme = {
11
11
  baseStyle: formsBaseTheme.inputGroupBaseStyle + " items-center justify-between",
12
12
  // Button wrapper style
13
13
  buttonWrapperStyle: "relative w-full",
14
- // Button style - bg-white for light mode only; dark mode bg comes from baseStyle (inputGroupBaseStyle)
15
- buttonStyle: "w-full cursor-pointer bg-white dark:bg-[var(--color-neutral-900)]",
14
+ // Button style - surface flips automatically between light/dark
15
+ buttonStyle: "w-full cursor-pointer bg-[var(--color-surface)]",
16
16
  // Placeholder text style - matches Input placeholder styling
17
17
  placeholderTextStyle: formsBaseTheme.placeholderStyle,
18
18
  // Selected value text style
19
- valueTextStyle: "text-[var(--color-text-primary)] dark:text-[var(--color-neutral-200)]",
19
+ valueTextStyle: "text-[var(--color-text-primary)]",
20
20
  // Size variants - composed from atomic tokens
21
21
  sizes: {
22
22
  sm: `${formsBaseTheme.sizes.sm.text} ${formsBaseTheme.sizes.sm.padding} ${formsBaseTheme.sizes.sm.height}`,
@@ -35,6 +35,7 @@ import '../../core/Dropdown/DropdownItem.js';
35
35
  import '../../core/Dropdown/DropdownSection.js';
36
36
  import '../../core/Dropdown/DropdownSeparator.js';
37
37
  import '../../core/Dropdown/Dropdown.theme.js';
38
+ import '../../core/DotSeparator/DotSeparator.js';
38
39
  import '../../core/Kbd/Kbd.js';
39
40
  import '../../core/MenuItem/MenuItem.js';
40
41
  import '../../core/Link/Link.js';
@@ -86,6 +87,8 @@ import '../../core/Sidebar/SidebarToggle.js';
86
87
  import '../../core/Sidebar/SidebarMobileTrigger.js';
87
88
  import '../../core/Sidebar/SidebarUserProfile.js';
88
89
  import '../../core/Sidebar/SidebarLogo.js';
90
+ import '../../core/Sidebar/SidebarSearch.js';
91
+ import '../../core/Sidebar/SidebarCard.js';
89
92
  import '../../core/Sidebar/SidebarContext.js';
90
93
  import '../../core/OfflineIndicator/OfflineIndicator.js';
91
94
  import '../../core/ContextMenu/ContextMenu.js';
@@ -25,7 +25,7 @@ const TimePickerTrigger = ({ id, disabled, isOpen, state = 'default', size = 'md
25
25
  const periodToggleStyle = theme.periodToggleStyle || "";
26
26
  // Apply focused styles when open — same pattern as SelectButton and DatePickerTrigger
27
27
  const activeFocusState = isOpen
28
- ? ((_d = theme.triggerFocusStates) === null || _d === void 0 ? void 0 : _d[state]) || "shadow-[inset_0_0_0_2px_var(--color-primary-600)] ring-4 ring-[var(--color-primary)]/10 dark:shadow-[inset_0_0_0_2px_var(--color-primary-500)] dark:ring-[var(--color-primary-500)]/20"
28
+ ? ((_d = theme.triggerFocusStates) === null || _d === void 0 ? void 0 : _d[state]) || "shadow-[inset_0_0_0_1px_var(--color-primary-600)] ring-4 ring-[var(--color-primary)]/10 dark:shadow-[inset_0_0_0_1px_var(--color-primary-500)] dark:ring-[var(--color-primary-500)]/20"
29
29
  : "";
30
30
  // Determine whether start icon is present (for input padding)
31
31
  const hasStartIcon = iconStart !== undefined ? Boolean(iconStart) : true;
@@ -9,11 +9,13 @@ const formsBaseTheme = {
9
9
  wrapperStyle: "relative w-full",
10
10
  // Common input group style with focus, hover, and state variations
11
11
  inputGroupBaseStyle: "relative flex rounded-[var(--form-radius)] outline-none shadow-[inset_0_0_0_1px_var(--color-border)] " +
12
- "focus-within:shadow-[inset_0_0_0_2px_var(--color-primary-600)] " +
13
- "focus-within:ring-4 focus-within:ring-[var(--color-primary)]/10 bg-white transition-all " +
14
- // Dark mode
15
- "dark:bg-[var(--color-neutral-900)] dark:shadow-[inset_0_0_0_1px_var(--color-neutral-700)] " +
16
- "dark:focus-within:shadow-[inset_0_0_0_2px_var(--color-primary-500)] dark:focus-within:ring-[var(--color-primary-500)]/20",
12
+ "focus-within:shadow-[inset_0_0_0_1px_var(--color-primary-600)] " +
13
+ "focus-within:ring-4 focus-within:ring-[var(--color-primary)]/10 bg-[var(--color-surface)] transition-all " +
14
+ // Hover edge: strengthen the border to --color-border-secondary on hover. Scoped with
15
+ // not-focus-within so focus (primary border) always wins; the token flips for dark mode.
16
+ "not-focus-within:hover:shadow-[inset_0_0_0_1px_var(--color-border-secondary)] " +
17
+ // Dark focus mirror (fill comes from --color-surface, which flips automatically)
18
+ "dark:focus-within:shadow-[inset_0_0_0_1px_var(--color-primary-500)] dark:focus-within:ring-[var(--color-primary-500)]/20",
17
19
  // Common base input/control style
18
20
  controlBaseStyle: "w-full bg-transparent text-sm text-[var(--color-text-primary)] " +
19
21
  "placeholder:text-[var(--color-text-placeholder)] focus:outline-none " +
@@ -45,24 +47,28 @@ const formsBaseTheme = {
45
47
  states: {
46
48
  default: "",
47
49
  disabled: "cursor-not-allowed bg-[var(--color-background-disabled)] shadow-[inset_0_0_0_1px_var(--color-border)] " +
50
+ // Suppress the hover-edge change while disabled (keep the resting border)
51
+ "not-focus-within:hover:shadow-[inset_0_0_0_1px_var(--color-border)] " +
48
52
  "[&_input]:text-[var(--color-text-disabled)] [&_textarea]:text-[var(--color-text-disabled)] " +
49
53
  "[&_select]:text-[var(--color-text-disabled)] [&_input]:cursor-not-allowed " +
50
54
  "[&_textarea]:cursor-not-allowed [&_select]:cursor-not-allowed " +
51
55
  "[&_input]:placeholder:text-[var(--color-text-placeholder)] " +
52
56
  "[&_textarea]:placeholder:text-[var(--color-text-placeholder)] " +
53
- "[&_select]:placeholder:text-[var(--color-text-placeholder)] [&_button]:cursor-not-allowed " +
54
- // Dark mode
55
- "dark:bg-[var(--color-neutral-800)] dark:shadow-[inset_0_0_0_1px_var(--color-neutral-700)]",
56
- invalid: "shadow-[inset_0_0_0_1px_var(--color-danger)] bg-[var(--color-danger-50)] focus-within:shadow-[inset_0_0_0_2px_var(--color-danger)] " +
57
+ "[&_select]:placeholder:text-[var(--color-text-placeholder)] [&_button]:cursor-not-allowed",
58
+ // (--color-background-disabled already flips for dark mode)
59
+ invalid: "shadow-[inset_0_0_0_1px_var(--color-danger)] bg-[var(--color-danger-50)] focus-within:shadow-[inset_0_0_0_1px_var(--color-danger)] " +
60
+ // Keep the danger border on hover (don't let the hover edge override it)
61
+ "not-focus-within:hover:shadow-[inset_0_0_0_1px_var(--color-danger)] " +
57
62
  // Dark mode
58
- "dark:bg-[var(--color-danger-950)]/30 dark:shadow-[inset_0_0_0_1px_var(--color-danger-500)]",
63
+ "dark:bg-[var(--color-danger-950)]/30 dark:shadow-[inset_0_0_0_1px_var(--color-danger-500)] " +
64
+ "dark:not-focus-within:hover:shadow-[inset_0_0_0_1px_var(--color-danger-500)]",
59
65
  },
60
66
  // Common focus state variants
61
67
  focusStates: {
62
- default: "shadow-[inset_0_0_0_2px_var(--color-primary-600)] ring-4 ring-[var(--color-primary)]/10 " +
63
- "dark:shadow-[inset_0_0_0_2px_var(--color-primary-500)] dark:ring-[var(--color-primary-500)]/20",
68
+ default: "shadow-[inset_0_0_0_1px_var(--color-primary-600)] ring-4 ring-[var(--color-primary)]/10 " +
69
+ "dark:shadow-[inset_0_0_0_1px_var(--color-primary-500)] dark:ring-[var(--color-primary-500)]/20",
64
70
  disabled: "shadow-none",
65
- invalid: "shadow-[inset_0_0_0_2px_var(--color-danger-500)] ring-4 ring-[var(--color-danger-500)]/10 " +
71
+ invalid: "shadow-[inset_0_0_0_1px_var(--color-danger-500)] ring-4 ring-[var(--color-danger-500)]/10 " +
66
72
  "dark:ring-[var(--color-danger-500)]/20",
67
73
  },
68
74
  // Common hover state variants
@@ -89,9 +95,8 @@ const formsBaseTheme = {
89
95
  dropdownStyles: {
90
96
  // Container for dropdown panel
91
97
  container: "fixed z-[1000] max-h-[var(--select-content-available-height,20rem)] overflow-auto overscroll-contain " +
92
- "rounded-[var(--form-radius)] bg-white/90 backdrop-blur-md text-sm border border-[var(--color-border)] " +
93
- "shadow-real-lg ring-1 ring-[var(--color-border)] focus:outline-none " +
94
- "dark:bg-[var(--color-neutral-900)]/90 dark:ring-[var(--color-neutral-700)]",
98
+ "rounded-[var(--form-radius)] bg-[var(--color-surface-overlay)]/90 backdrop-blur-md text-sm border border-[var(--color-border)] " +
99
+ "shadow-real-lg ring-1 ring-[var(--color-border)] focus:outline-none",
95
100
  // Base option style
96
101
  option: "relative cursor-pointer select-none py-2 px-3 text-[var(--color-text-primary)] " +
97
102
  "hover:text-[var(--color-primary)] hover:bg-[var(--color-primary-50)]/50 " +
@@ -58,6 +58,7 @@ import '../core/Dropdown/DropdownItem.js';
58
58
  import '../core/Dropdown/DropdownSection.js';
59
59
  import '../core/Dropdown/DropdownSeparator.js';
60
60
  import '../core/Dropdown/Dropdown.theme.js';
61
+ import '../core/DotSeparator/DotSeparator.js';
61
62
  import '../core/Kbd/Kbd.js';
62
63
  import '../core/MenuItem/MenuItem.js';
63
64
  import '../core/Link/Link.js';
@@ -108,6 +109,8 @@ import '../core/Sidebar/SidebarToggle.js';
108
109
  import '../core/Sidebar/SidebarMobileTrigger.js';
109
110
  import '../core/Sidebar/SidebarUserProfile.js';
110
111
  import '../core/Sidebar/SidebarLogo.js';
112
+ import '../core/Sidebar/SidebarSearch.js';
113
+ import '../core/Sidebar/SidebarCard.js';
111
114
  import '../core/Sidebar/SidebarContext.js';
112
115
  import '../core/OfflineIndicator/OfflineIndicator.js';
113
116
  import '../core/ContextMenu/ContextMenu.js';
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import type { AppShellProps } from "./AppShell.types";
3
+ export declare const AppShell: React.ForwardRefExoticComponent<AppShellProps & React.RefAttributes<HTMLDivElement>> & {
4
+ Topbar: React.ForwardRefExoticComponent<import("./AppShell.types").AppShellTopbarProps & React.RefAttributes<HTMLElement>>;
5
+ Sidebar: React.ForwardRefExoticComponent<import("./AppShell.types").AppShellSidebarProps & React.RefAttributes<HTMLElement>>;
6
+ Header: React.ForwardRefExoticComponent<import("./AppShell.types").AppShellHeaderProps & React.RefAttributes<HTMLElement>>;
7
+ Main: React.ForwardRefExoticComponent<import("./AppShell.types").AppShellMainProps & React.RefAttributes<HTMLElement>>;
8
+ RightPanel: React.ForwardRefExoticComponent<import("./AppShell.types").AppShellRightPanelProps & React.RefAttributes<HTMLElement>>;
9
+ Footer: React.ForwardRefExoticComponent<import("./AppShell.types").AppShellFooterProps & React.RefAttributes<HTMLElement>>;
10
+ };
@@ -0,0 +1,84 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import React__default from 'react';
3
+ import { cn } from '../../../utils/cn.js';
4
+ import { getAppShellTheme } from './AppShell.theme.js';
5
+ import { AppShellProvider } from './AppShellContext.js';
6
+ import { AppShellTopbar } from './AppShellTopbar.js';
7
+ import { AppShellSidebar } from './AppShellSidebar.js';
8
+ import { AppShellHeader } from './AppShellHeader.js';
9
+ import { AppShellMain } from './AppShellMain.js';
10
+ import { AppShellRightPanel } from './AppShellRightPanel.js';
11
+ import { AppShellFooter } from './AppShellFooter.js';
12
+
13
+ const AppShellRoot = React__default.forwardRef(({ className, theme: customTheme, scroll = "viewport", topbarSpan = "full", footerSpan = "full", contentWidth = "full", contentPadding = "md", children, ...props }, ref) => {
14
+ const theme = getAppShellTheme(customTheme);
15
+ const contextValue = React__default.useMemo(() => ({ scroll, contentWidth, contentPadding }), [scroll, contentWidth, contentPadding]);
16
+ // Bucket children by slot type. Header is intentionally NOT bucketed —
17
+ // it is user-composed inside AppShell.Main.
18
+ let topbar = null;
19
+ let sidebar = null;
20
+ let main = null;
21
+ let rightPanel = null;
22
+ let footer = null;
23
+ React__default.Children.forEach(children, (child) => {
24
+ if (!React__default.isValidElement(child))
25
+ return;
26
+ const type = child.type;
27
+ if (type === AppShellTopbar) {
28
+ if (topbar === null)
29
+ topbar = child;
30
+ else if (process.env.NODE_ENV !== "production") {
31
+ console.warn("[AppShell]: multiple AppShell.Topbar children; keeping the first.");
32
+ }
33
+ }
34
+ else if (type === AppShellSidebar) {
35
+ if (sidebar === null)
36
+ sidebar = child;
37
+ else if (process.env.NODE_ENV !== "production") {
38
+ console.warn("[AppShell]: multiple AppShell.Sidebar children; keeping the first.");
39
+ }
40
+ }
41
+ else if (type === AppShellMain) {
42
+ if (main === null)
43
+ main = child;
44
+ else if (process.env.NODE_ENV !== "production") {
45
+ console.warn("[AppShell]: multiple AppShell.Main children; keeping the first.");
46
+ }
47
+ }
48
+ else if (type === AppShellRightPanel) {
49
+ if (rightPanel === null)
50
+ rightPanel = child;
51
+ else if (process.env.NODE_ENV !== "production") {
52
+ console.warn("[AppShell]: multiple AppShell.RightPanel children; keeping the first.");
53
+ }
54
+ }
55
+ else if (type === AppShellFooter) {
56
+ if (footer === null)
57
+ footer = child;
58
+ else if (process.env.NODE_ENV !== "production") {
59
+ console.warn("[AppShell]: multiple AppShell.Footer children; keeping the first.");
60
+ }
61
+ }
62
+ else if (process.env.NODE_ENV !== "production") {
63
+ console.warn("[AppShell]: unknown child rendered; expected one of " +
64
+ "AppShell.Topbar / Sidebar / Main / RightPanel / Footer. " +
65
+ "AppShell.Header is composed inside AppShell.Main.");
66
+ }
67
+ });
68
+ const topbarInChrome = topbar !== null && topbarSpan === "full";
69
+ const topbarInMain = topbar !== null && topbarSpan === "main";
70
+ const footerInChrome = footer !== null && footerSpan === "full";
71
+ const footerInMain = footer !== null && footerSpan === "main";
72
+ return (jsx(AppShellProvider, { value: contextValue, children: jsxs("div", { ref: ref, className: cn(theme.root, scroll === "viewport" && theme.rootViewport, className), ...props, children: [topbarInChrome && topbar, jsxs("div", { className: theme.shell, children: [sidebar, jsxs("div", { className: theme.mainColumn, children: [topbarInMain && topbar, main, footerInMain && footer] }), rightPanel] }), footerInChrome && footer] }) }));
73
+ });
74
+ AppShellRoot.displayName = "AppShell";
75
+ const AppShell = Object.assign(AppShellRoot, {
76
+ Topbar: AppShellTopbar,
77
+ Sidebar: AppShellSidebar,
78
+ Header: AppShellHeader,
79
+ Main: AppShellMain,
80
+ RightPanel: AppShellRightPanel,
81
+ Footer: AppShellFooter,
82
+ });
83
+
84
+ export { AppShell };
@@ -0,0 +1,3 @@
1
+ import type { AppShellTheme, AppShellThemeOverrides } from "./AppShell.types";
2
+ export declare const appShellTheme: AppShellTheme;
3
+ export declare const getAppShellTheme: (customTheme?: AppShellThemeOverrides) => AppShellTheme;
@@ -0,0 +1,42 @@
1
+ const appShellTheme = {
2
+ root: "flex flex-col bg-[var(--color-background)] text-[var(--color-text-primary)]",
3
+ rootViewport: "h-screen overflow-hidden",
4
+ shell: "flex flex-1 min-h-0 min-w-0",
5
+ mainColumn: "flex flex-col flex-1 min-h-0 min-w-0",
6
+ topbar: "shrink-0 border-b border-[var(--color-border)] bg-[var(--color-background)]/90 backdrop-blur supports-[backdrop-filter]:bg-[var(--color-background)]/75",
7
+ sidebar: "flex flex-col shrink-0 overflow-hidden border-r border-[var(--color-border)] bg-[var(--color-background)]/95 backdrop-blur supports-[backdrop-filter]:bg-[var(--color-background)]/85",
8
+ sidebarScroll: "min-h-0 flex-1",
9
+ sidebarCollapsed: "hidden lg:flex",
10
+ header: "shrink-0 border-b border-[var(--color-border)] bg-[var(--color-background)]/90 backdrop-blur supports-[backdrop-filter]:bg-[var(--color-background)]/75",
11
+ main: "flex flex-col flex-1 min-h-0 min-w-0",
12
+ mainScroll: "min-h-0 flex-1",
13
+ mainInner: "mx-auto w-full",
14
+ rightPanel: "flex flex-col shrink-0 overflow-hidden border-l border-[var(--color-border)] bg-[var(--color-background)]/95 backdrop-blur supports-[backdrop-filter]:bg-[var(--color-background)]/85",
15
+ rightPanelScroll: "min-h-0 flex-1",
16
+ footer: "shrink-0 border-t border-[var(--color-border)] bg-[var(--color-background)]/90 backdrop-blur supports-[backdrop-filter]:bg-[var(--color-background)]/75",
17
+ contentPadding: {
18
+ none: "p-0",
19
+ sm: "p-3 sm:p-4",
20
+ md: "p-4 sm:p-6 lg:p-8",
21
+ lg: "p-5 sm:p-8 lg:p-10",
22
+ },
23
+ contentWidth: {
24
+ full: "max-w-none",
25
+ wide: "max-w-7xl",
26
+ contained: "max-w-5xl",
27
+ },
28
+ };
29
+ const getAppShellTheme = (customTheme) => ({
30
+ ...appShellTheme,
31
+ ...customTheme,
32
+ contentPadding: {
33
+ ...appShellTheme.contentPadding,
34
+ ...customTheme === null || customTheme === void 0 ? void 0 : customTheme.contentPadding,
35
+ },
36
+ contentWidth: {
37
+ ...appShellTheme.contentWidth,
38
+ ...customTheme === null || customTheme === void 0 ? void 0 : customTheme.contentWidth,
39
+ },
40
+ });
41
+
42
+ export { appShellTheme, getAppShellTheme };
@@ -0,0 +1,127 @@
1
+ import React from "react";
2
+ export type AppShellScroll = "viewport" | "page";
3
+ export type AppShellSpan = "full" | "main";
4
+ export type AppShellContentWidth = "full" | "wide" | "contained";
5
+ export type AppShellContentPadding = "none" | "sm" | "md" | "lg";
6
+ export interface AppShellTheme {
7
+ /** Outer root container (column layout). */
8
+ root: string;
9
+ /** Extra classes applied when `scroll="viewport"`. */
10
+ rootViewport: string;
11
+ /** Row container holding sidebar / main column / right panel. */
12
+ shell: string;
13
+ /** The middle column (Topbar-in-main? Main, Footer-in-main?). */
14
+ mainColumn: string;
15
+ topbar: string;
16
+ sidebar: string;
17
+ sidebarScroll: string;
18
+ sidebarCollapsed: string;
19
+ header: string;
20
+ main: string;
21
+ mainScroll: string;
22
+ mainInner: string;
23
+ rightPanel: string;
24
+ rightPanelScroll: string;
25
+ footer: string;
26
+ contentPadding: Record<AppShellContentPadding, string>;
27
+ contentWidth: Record<AppShellContentWidth, string>;
28
+ }
29
+ export interface AppShellThemeOverrides {
30
+ root?: string;
31
+ rootViewport?: string;
32
+ shell?: string;
33
+ mainColumn?: string;
34
+ topbar?: string;
35
+ sidebar?: string;
36
+ sidebarScroll?: string;
37
+ sidebarCollapsed?: string;
38
+ header?: string;
39
+ main?: string;
40
+ mainScroll?: string;
41
+ mainInner?: string;
42
+ rightPanel?: string;
43
+ rightPanelScroll?: string;
44
+ footer?: string;
45
+ contentPadding?: Partial<Record<AppShellContentPadding, string>>;
46
+ contentWidth?: Partial<Record<AppShellContentWidth, string>>;
47
+ }
48
+ export interface AppShellProps extends React.HTMLAttributes<HTMLDivElement> {
49
+ /**
50
+ * Scroll model. `"viewport"` makes the root `h-screen overflow-hidden`
51
+ * and only `Main` scrolls. `"page"` lets the whole document scroll.
52
+ * @default "viewport"
53
+ */
54
+ scroll?: AppShellScroll;
55
+ /**
56
+ * Whether the Topbar spans the full viewport width (over the Sidebar)
57
+ * or only sits above Main + RightPanel.
58
+ * @default "full"
59
+ */
60
+ topbarSpan?: AppShellSpan;
61
+ /**
62
+ * Whether the Footer spans the full viewport width (under the Sidebar)
63
+ * or only sits below Main + RightPanel.
64
+ * @default "full"
65
+ */
66
+ footerSpan?: AppShellSpan;
67
+ /**
68
+ * Max content width applied to AppShell.Main when not overridden.
69
+ * @default "full"
70
+ */
71
+ contentWidth?: AppShellContentWidth;
72
+ /**
73
+ * Responsive content padding applied to AppShell.Main when not overridden.
74
+ * @default "md"
75
+ */
76
+ contentPadding?: AppShellContentPadding;
77
+ /**
78
+ * Theme overrides for the AppShell root wrapper (root, shell, mainColumn).
79
+ * Style individual slots via their own `theme` props on each sub-component.
80
+ */
81
+ theme?: AppShellThemeOverrides;
82
+ }
83
+ export interface AppShellTopbarProps extends React.HTMLAttributes<HTMLElement> {
84
+ /** Stick to top of chrome. Only meaningful when `scroll="page"`. @default true */
85
+ sticky?: boolean;
86
+ /** Theme overrides. */
87
+ theme?: AppShellThemeOverrides;
88
+ }
89
+ export interface AppShellSidebarProps extends React.HTMLAttributes<HTMLElement> {
90
+ /** CSS width value. @default "16rem" */
91
+ width?: string;
92
+ /** Hide on mobile (below `lg`). @default true */
93
+ collapsedOnMobile?: boolean;
94
+ /** Theme overrides. */
95
+ theme?: AppShellThemeOverrides;
96
+ }
97
+ export interface AppShellHeaderProps extends React.HTMLAttributes<HTMLElement> {
98
+ /**
99
+ * Stick to top of the scrolling Main region. Header sticks at its position
100
+ * inside Main's content padding; for a flush edge-to-edge sticky bar, use
101
+ * AppShell.Topbar instead.
102
+ * @default true
103
+ */
104
+ sticky?: boolean;
105
+ /** Theme overrides. */
106
+ theme?: AppShellThemeOverrides;
107
+ }
108
+ export interface AppShellMainProps extends React.HTMLAttributes<HTMLElement> {
109
+ /** Max content width. Inherits from AppShell when omitted. */
110
+ contentWidth?: AppShellContentWidth;
111
+ /** Responsive padding. Inherits from AppShell when omitted. */
112
+ contentPadding?: AppShellContentPadding;
113
+ /** Theme overrides. */
114
+ theme?: AppShellThemeOverrides;
115
+ }
116
+ export interface AppShellRightPanelProps extends React.HTMLAttributes<HTMLElement> {
117
+ /** CSS width value. @default "20rem" */
118
+ width?: string;
119
+ /** Theme overrides. */
120
+ theme?: AppShellThemeOverrides;
121
+ }
122
+ export interface AppShellFooterProps extends React.HTMLAttributes<HTMLElement> {
123
+ /** Stick to bottom of chrome. Only meaningful when `scroll="page"`. @default true */
124
+ sticky?: boolean;
125
+ /** Theme overrides. */
126
+ theme?: AppShellThemeOverrides;
127
+ }
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import type { AppShellContentPadding, AppShellContentWidth, AppShellScroll } from "./AppShell.types";
3
+ export interface AppShellContextValue {
4
+ scroll: AppShellScroll;
5
+ contentWidth: AppShellContentWidth;
6
+ contentPadding: AppShellContentPadding;
7
+ }
8
+ export declare const AppShellProvider: React.Provider<AppShellContextValue | undefined>;
9
+ /**
10
+ * Reads AppShell root context. Returns sensible defaults when used outside
11
+ * an `<AppShell>` (so individual slot components remain usable standalone
12
+ * for testing or partial composition).
13
+ */
14
+ export declare const useAppShellContext: () => AppShellContextValue;
@@ -0,0 +1,19 @@
1
+ import React__default from 'react';
2
+
3
+ const AppShellContext = React__default.createContext(undefined);
4
+ const AppShellProvider = AppShellContext.Provider;
5
+ /**
6
+ * Reads AppShell root context. Returns sensible defaults when used outside
7
+ * an `<AppShell>` (so individual slot components remain usable standalone
8
+ * for testing or partial composition).
9
+ */
10
+ const useAppShellContext = () => {
11
+ const ctx = React__default.useContext(AppShellContext);
12
+ return (ctx !== null && ctx !== void 0 ? ctx : {
13
+ scroll: "viewport",
14
+ contentWidth: "full",
15
+ contentPadding: "md",
16
+ });
17
+ };
18
+
19
+ export { AppShellProvider, useAppShellContext };
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ import type { AppShellFooterProps } from "./AppShell.types";
3
+ export declare const AppShellFooter: React.ForwardRefExoticComponent<AppShellFooterProps & React.RefAttributes<HTMLElement>>;