@flikk/ui 1.0.0-beta.25 → 1.0.0-beta.26
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.
- package/dist/components/ai/CodeBlock/CodeBlock.theme.js +2 -2
- package/dist/components/ai/PromptInput/PromptInput.js +1 -0
- package/dist/components/ai/PromptInput/VoiceRecorder.js +1 -0
- package/dist/components/ai/StreamingResponse/MarkdownRenderer.js +1 -1
- package/dist/components/ai/TokenCounter/TokenCounter.theme.js +1 -1
- package/dist/components/charts/BarChart/BarChart.js +2 -2
- package/dist/components/charts/StackedBarChart/StackedBarChart.js +1 -1
- package/dist/components/charts/shared/BarRenderer/BarRenderer.js +2 -2
- package/dist/components/core/Breadcrumbs/Breadcrumbs.theme.js +1 -1
- package/dist/components/core/Button/Button.js +1 -1
- package/dist/components/core/Button/Button.theme.js +4 -4
- package/dist/components/core/Calendar/CalendarMini/CalendarMini.theme.js +1 -1
- package/dist/components/core/ContextMenu/ContextMenu.theme.js +1 -1
- package/dist/components/core/Drawer/Drawer.theme.js +2 -2
- package/dist/components/core/Dropdown/Dropdown.theme.js +2 -2
- package/dist/components/core/Empty/Empty.js +1 -1
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.d.ts +14 -0
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.js +28 -0
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.theme.d.ts +6 -0
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.theme.js +8 -0
- package/dist/components/core/ImagePlaceholder/ImagePlaceholder.types.d.ts +32 -0
- package/dist/components/core/ImagePlaceholder/index.d.ts +2 -0
- package/dist/components/core/Message/Message.theme.js +1 -1
- package/dist/components/core/Modal/Modal.theme.js +1 -1
- package/dist/components/core/NavItem/NavItem.d.ts +1 -1
- package/dist/components/core/NavItem/NavItem.js +171 -68
- package/dist/components/core/NavItem/NavItem.theme.js +20 -12
- package/dist/components/core/NavItem/NavItem.types.d.ts +17 -39
- package/dist/components/core/Pagination/Pagination.theme.js +3 -3
- package/dist/components/core/Popover/Popover.theme.js +1 -1
- package/dist/components/core/Progress/Progress.theme.js +1 -1
- package/dist/components/core/ScrollArea/ScrollArea.js +2 -2
- package/dist/components/core/ScrollArea/ScrollArea.theme.js +1 -1
- package/dist/components/core/Segmented/Segmented.js +8 -6
- package/dist/components/core/Segmented/Segmented.theme.js +3 -3
- package/dist/components/core/Sidebar/Sidebar.d.ts +1 -1
- package/dist/components/core/Sidebar/Sidebar.js +42 -13
- package/dist/components/core/Sidebar/Sidebar.theme.js +5 -7
- package/dist/components/core/Sidebar/Sidebar.types.d.ts +33 -4
- package/dist/components/core/Sidebar/SidebarContent.js +6 -6
- package/dist/components/core/Sidebar/SidebarContext.d.ts +17 -16
- package/dist/components/core/Sidebar/SidebarContext.js +42 -19
- package/dist/components/core/Sidebar/SidebarFooter.js +4 -6
- package/dist/components/core/Sidebar/SidebarHeader.js +4 -9
- package/dist/components/core/Sidebar/SidebarLogo.js +3 -7
- package/dist/components/core/Sidebar/SidebarNav.js +4 -3
- package/dist/components/core/Sidebar/SidebarNavGroup.js +4 -7
- package/dist/components/core/Sidebar/SidebarToggle.js +6 -1
- package/dist/components/core/Sidebar/SidebarUserProfile.js +33 -17
- package/dist/components/core/Sidebar/index.d.ts +2 -3
- package/dist/components/core/Skeleton/Skeleton.theme.js +1 -1
- package/dist/components/core/Spinner/Spinner.theme.js +1 -1
- package/dist/components/core/Tabs/Tabs.js +6 -1
- package/dist/components/core/Tabs/Tabs.types.d.ts +2 -0
- package/dist/components/core/Tabs/TabsBody.js +5 -3
- package/dist/components/core/Tag/Tag.theme.js +1 -1
- package/dist/components/core/index.d.ts +1 -0
- package/dist/components/core/index.js +2 -2
- package/dist/components/data-display/GanttChart/GanttTableGroupRow.js +1 -1
- package/dist/components/data-display/KPI/KPI.js +13 -3
- package/dist/components/data-display/KPI/KPI.theme.js +3 -3
- package/dist/components/data-display/Metric/Metric.theme.js +3 -3
- package/dist/components/data-display/Table/Table.js +4 -3
- package/dist/components/data-display/Table/Table.theme.js +11 -1
- package/dist/components/data-display/Table/Table.types.d.ts +15 -0
- package/dist/components/data-display/Table/TableColumnManager.js +1 -1
- package/dist/components/data-display/Table/index.d.ts +2 -2
- package/dist/components/effects/Aurora/Aurora.js +79 -40
- package/dist/components/effects/InteractiveCharacters/InteractiveCharacters.js +3 -3
- package/dist/components/effects/InteractiveCharacters/characters/BlobCharacter.js +13 -4
- package/dist/components/effects/InteractiveCharacters/characters/SmallCharacter.js +13 -4
- package/dist/components/effects/InteractiveCharacters/characters/TallCharacter.js +14 -4
- package/dist/components/effects/MorphingText/MorphingText.js +40 -7
- package/dist/components/effects/StripePattern/StripePattern.d.ts +18 -0
- package/dist/components/effects/StripePattern/StripePattern.js +54 -0
- package/dist/components/effects/StripePattern/StripePattern.types.d.ts +53 -0
- package/dist/components/effects/StripePattern/index.d.ts +2 -0
- package/dist/components/effects/index.d.ts +2 -0
- package/dist/components/effects/index.js +1 -0
- package/dist/components/forms/Checkbox/Checkbox.theme.js +1 -1
- package/dist/components/forms/CronInput/CronInput.theme.js +16 -16
- package/dist/components/forms/DatePicker/DatePickerTrigger.js +1 -1
- package/dist/components/forms/DateRangePicker/DateRangePicker.theme.js +1 -1
- package/dist/components/forms/DateRangePicker/DateRangePickerTrigger.js +1 -1
- package/dist/components/forms/FileUpload/FileUpload.js +1 -1
- package/dist/components/forms/FileUpload/FileUploadProgress.js +27 -20
- package/dist/components/forms/FileUpload/FileUploadProgress.theme.js +2 -2
- package/dist/components/forms/Input/Input.theme.js +9 -11
- package/dist/components/forms/Mention/Mention.theme.js +3 -3
- package/dist/components/forms/Radio/Radio.theme.js +1 -1
- package/dist/components/forms/RichTextEditor/RichTextEditor.d.ts +18 -0
- package/dist/components/forms/RichTextEditor/RichTextEditor.js +1231 -236
- package/dist/components/forms/RichTextEditor/RichTextEditor.theme.d.ts +53 -1
- package/dist/components/forms/RichTextEditor/RichTextEditor.theme.js +99 -25
- package/dist/components/forms/RichTextEditor/RichTextEditor.types.d.ts +42 -3
- package/dist/components/forms/RichTextEditor/index.d.ts +2 -2
- package/dist/components/forms/Select/Select.js +1 -1
- package/dist/components/forms/Slider/Slider.theme.js +1 -1
- package/dist/components/forms/Switch/Switch.theme.js +1 -1
- package/dist/components/forms/TimePicker/TimePicker.theme.js +2 -2
- package/dist/components/forms/TimePicker/TimePickerContent.js +1 -0
- package/dist/components/forms/TimePicker/TimePickerTrigger.js +1 -1
- package/dist/components/forms/forms.theme.js +12 -12
- package/dist/components/forms/index.js +1 -0
- package/dist/components/layout/FormLayout/FormLayout.js +6 -4
- package/dist/components/layout/FormLayout/FormLayout.types.d.ts +3 -3
- package/dist/components/layout/FormLayout/FormLayoutSection.js +6 -1
- package/dist/components/layout/PageLayout/PageLayout.d.ts +2 -2
- package/dist/components/layout/PageLayout/PageLayout.js +23 -5
- package/dist/components/layout/PageLayout/PageLayout.theme.d.ts +2 -1
- package/dist/components/layout/PageLayout/PageLayout.theme.js +35 -6
- package/dist/components/layout/PageLayout/PageLayout.types.d.ts +45 -0
- package/dist/components/layout/PageLayout/PageLayoutContent.js +6 -4
- package/dist/components/layout/PageLayout/PageLayoutHeader.js +3 -3
- package/dist/components/layout/PageLayout/PageLayoutSidebar.js +5 -3
- package/dist/components/layout/PageLayout/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/styles/theme.css +127 -92
- package/dist/components/core/Sidebar/SidebarSubmenu.d.ts +0 -7
- package/dist/components/core/Sidebar/SidebarSubmenu.js +0 -12
|
@@ -1,8 +1,60 @@
|
|
|
1
1
|
import { RichTextEditorTheme, ColorOption } from "./RichTextEditor.types";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Legacy 10-entry color list — kept for backwards compat with consumers that
|
|
4
|
+
* import `colorOptions` directly. The RichTextEditor's color picker now uses
|
|
5
|
+
* the full Tailwind spectrum below.
|
|
4
6
|
*/
|
|
5
7
|
export declare const colorOptions: ColorOption[];
|
|
8
|
+
/**
|
|
9
|
+
* Tailwind shade scale (same for every family). Used by both the picker
|
|
10
|
+
* UI and the `getTailwindShadeTokens` utility below.
|
|
11
|
+
*/
|
|
12
|
+
export declare const TAILWIND_SHADE_LABELS: readonly ["50", "100", "200", "300", "400", "500", "600", "700", "800", "900", "950"];
|
|
13
|
+
/**
|
|
14
|
+
* The 22 Tailwind color families, in spectrum order.
|
|
15
|
+
* Tailwind v4 exposes each shade as `--color-{family}-{shade}` automatically,
|
|
16
|
+
* so we render swatches via `var(--color-...)` instead of hardcoding hex.
|
|
17
|
+
*/
|
|
18
|
+
export declare const TAILWIND_COLOR_FAMILIES: readonly ["slate", "gray", "zinc", "neutral", "stone", "red", "orange", "amber", "yellow", "lime", "green", "emerald", "teal", "cyan", "sky", "blue", "indigo", "violet", "purple", "fuchsia", "pink", "rose"];
|
|
19
|
+
/**
|
|
20
|
+
* Returns shade tokens for a given Tailwind family.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* getTailwindShadeTokens("slate")
|
|
24
|
+
* // → ["slate-50", "slate-100", "slate-200", ..., "slate-950"]
|
|
25
|
+
*/
|
|
26
|
+
export declare const getTailwindShadeTokens: (family: string) => string[];
|
|
27
|
+
/**
|
|
28
|
+
* Resolves a Tailwind shade token to a CSS color value usable in inline
|
|
29
|
+
* styles for swatch backgrounds. Reads `--color-{token}` directly; modern
|
|
30
|
+
* browsers accept the resulting `oklch(...)` (or fallback `rgb()`) in
|
|
31
|
+
* `background-color` without normalization.
|
|
32
|
+
*
|
|
33
|
+
* SSR-safe: returns `var(--color-{token})` literal when document is absent.
|
|
34
|
+
*/
|
|
35
|
+
export declare const resolveTailwindColor: (token: string) => string;
|
|
36
|
+
/**
|
|
37
|
+
* Tailwind v4 only emits `--color-{family}-{shade}` CSS vars for shades that
|
|
38
|
+
* appear as utility classes in source. Since the picker resolves them at
|
|
39
|
+
* runtime via `var(...)`, we need every shade present. This sentinel string
|
|
40
|
+
* lists `bg-{family}-{shade}` for the full 22×11 palette so Tailwind's
|
|
41
|
+
* content scanner emits all CSS variables. Not used at runtime.
|
|
42
|
+
*/
|
|
43
|
+
export declare const _TAILWIND_PALETTE_KEEPALIVE: string;
|
|
44
|
+
/**
|
|
45
|
+
* The two non-family base colors users always reach for, shown in their own row
|
|
46
|
+
* above the spectrum.
|
|
47
|
+
*
|
|
48
|
+
* `value` is the resolved background color (used to paint the swatch);
|
|
49
|
+
* `token` is the Tailwind shade fragment used to build the `text-{token}`
|
|
50
|
+
* class applied to the editor content.
|
|
51
|
+
*/
|
|
52
|
+
export declare const MONO_COLORS: {
|
|
53
|
+
name: string;
|
|
54
|
+
value: string;
|
|
55
|
+
token: string;
|
|
56
|
+
}[];
|
|
57
|
+
export declare const _RTE_CLASSES_KEEPALIVE: string;
|
|
6
58
|
/**
|
|
7
59
|
* Rich Text Editor theme - extends common forms base theme for consistency
|
|
8
60
|
*/
|
|
@@ -1,19 +1,87 @@
|
|
|
1
1
|
import { formsBaseTheme } from '../forms.theme.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Tailwind shade scale (same for every family). Used by both the picker
|
|
5
|
+
* UI and the `getTailwindShadeTokens` utility below.
|
|
5
6
|
*/
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
const TAILWIND_SHADE_LABELS = [
|
|
8
|
+
"50",
|
|
9
|
+
"100",
|
|
10
|
+
"200",
|
|
11
|
+
"300",
|
|
12
|
+
"400",
|
|
13
|
+
"500",
|
|
14
|
+
"600",
|
|
15
|
+
"700",
|
|
16
|
+
"800",
|
|
17
|
+
"900",
|
|
18
|
+
"950",
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* The 22 Tailwind color families, in spectrum order.
|
|
22
|
+
* Tailwind v4 exposes each shade as `--color-{family}-{shade}` automatically,
|
|
23
|
+
* so we render swatches via `var(--color-...)` instead of hardcoding hex.
|
|
24
|
+
*/
|
|
25
|
+
const TAILWIND_COLOR_FAMILIES = [
|
|
26
|
+
"slate",
|
|
27
|
+
"gray",
|
|
28
|
+
"zinc",
|
|
29
|
+
"neutral",
|
|
30
|
+
"stone",
|
|
31
|
+
"red",
|
|
32
|
+
"orange",
|
|
33
|
+
"amber",
|
|
34
|
+
"yellow",
|
|
35
|
+
"lime",
|
|
36
|
+
"green",
|
|
37
|
+
"emerald",
|
|
38
|
+
"teal",
|
|
39
|
+
"cyan",
|
|
40
|
+
"sky",
|
|
41
|
+
"blue",
|
|
42
|
+
"indigo",
|
|
43
|
+
"violet",
|
|
44
|
+
"purple",
|
|
45
|
+
"fuchsia",
|
|
46
|
+
"pink",
|
|
47
|
+
"rose",
|
|
48
|
+
];
|
|
49
|
+
/**
|
|
50
|
+
* Returns shade tokens for a given Tailwind family.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* getTailwindShadeTokens("slate")
|
|
54
|
+
* // → ["slate-50", "slate-100", "slate-200", ..., "slate-950"]
|
|
55
|
+
*/
|
|
56
|
+
const getTailwindShadeTokens = (family) => TAILWIND_SHADE_LABELS.map((shade) => `${family}-${shade}`);
|
|
57
|
+
/**
|
|
58
|
+
* Resolves a Tailwind shade token to a CSS color value usable in inline
|
|
59
|
+
* styles for swatch backgrounds. Reads `--color-{token}` directly; modern
|
|
60
|
+
* browsers accept the resulting `oklch(...)` (or fallback `rgb()`) in
|
|
61
|
+
* `background-color` without normalization.
|
|
62
|
+
*
|
|
63
|
+
* SSR-safe: returns `var(--color-{token})` literal when document is absent.
|
|
64
|
+
*/
|
|
65
|
+
const resolveTailwindColor = (token) => {
|
|
66
|
+
const cssVar = `--color-${token}`;
|
|
67
|
+
if (typeof window === "undefined")
|
|
68
|
+
return `var(${cssVar})`;
|
|
69
|
+
const resolved = getComputedStyle(document.documentElement)
|
|
70
|
+
.getPropertyValue(cssVar)
|
|
71
|
+
.trim();
|
|
72
|
+
return resolved || `var(${cssVar})`;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* The two non-family base colors users always reach for, shown in their own row
|
|
76
|
+
* above the spectrum.
|
|
77
|
+
*
|
|
78
|
+
* `value` is the resolved background color (used to paint the swatch);
|
|
79
|
+
* `token` is the Tailwind shade fragment used to build the `text-{token}`
|
|
80
|
+
* class applied to the editor content.
|
|
81
|
+
*/
|
|
82
|
+
const MONO_COLORS = [
|
|
83
|
+
{ name: "white", value: "#ffffff", token: "white" },
|
|
84
|
+
{ name: "black", value: "#000000", token: "black" },
|
|
17
85
|
];
|
|
18
86
|
/**
|
|
19
87
|
* Rich Text Editor theme - extends common forms base theme for consistency
|
|
@@ -25,20 +93,26 @@ const richTextEditorTheme = {
|
|
|
25
93
|
containerStyle: `${formsBaseTheme.inputGroupBaseStyle} flex-col min-h-[120px] overflow-hidden`,
|
|
26
94
|
// Editor content area - extends common control base style
|
|
27
95
|
editorStyle: `${formsBaseTheme.controlBaseStyle} min-h-[100px] px-3 py-2 resize-none overflow-y-auto [&_p]:my-1 [&_p:first-child]:mt-0 [&_p:last-child]:mb-0 [&_strong]:font-semibold [&_em]:italic [&_u]:underline data-[state=disabled]:cursor-not-allowed empty:before:content-[attr(data-placeholder)] empty:before:text-[var(--color-text-placeholder)] empty:before:pointer-events-none`,
|
|
28
|
-
// Toolbar styling (
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
96
|
+
// Toolbar styling (docked variant)
|
|
97
|
+
// `rounded-t-[var(--form-radius)]` matches the container's radius so the
|
|
98
|
+
// toolbar's own bg/backdrop-blur respects the top corners — prevents the
|
|
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)]",
|
|
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",
|
|
103
|
+
// Toolbar button — single source of truth via data-[state=active]
|
|
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",
|
|
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",
|
|
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)]",
|
|
36
110
|
// Separator between toolbar sections
|
|
37
111
|
separatorStyle: "w-px h-6 bg-[var(--color-border)] mx-1",
|
|
38
|
-
// Color picker
|
|
39
|
-
colorPickerStyle: "flex flex-
|
|
40
|
-
// Color swatch button
|
|
41
|
-
colorSwatchStyle: "size-6 rounded-[calc(var(--radius-base)*0.75)] cursor-pointer hover:scale-105 transition-transform focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] focus:ring-offset-1",
|
|
112
|
+
// Color picker layout — column of family rows, plus optional Recent + Mono rows
|
|
113
|
+
colorPickerStyle: "flex flex-col gap-1 p-2 w-fit",
|
|
114
|
+
// Color swatch button (original size + rounding)
|
|
115
|
+
colorSwatchStyle: "size-6 rounded-[calc(var(--radius-base)*0.75)] cursor-pointer hover:scale-105 transition-transform focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] focus:ring-offset-1 data-[active=true]:ring-2 data-[active=true]:ring-[var(--color-primary)] data-[active=true]:ring-offset-1 border border-[var(--color-border)]",
|
|
42
116
|
// Size variants - use common form sizes for consistency
|
|
43
117
|
sizes: {
|
|
44
118
|
sm: `${formsBaseTheme.sizes.sm.text} min-h-[80px]`,
|
|
@@ -51,4 +125,4 @@ const richTextEditorTheme = {
|
|
|
51
125
|
helperText: formsBaseTheme.helperText,
|
|
52
126
|
};
|
|
53
127
|
|
|
54
|
-
export {
|
|
128
|
+
export { MONO_COLORS, TAILWIND_COLOR_FAMILIES, TAILWIND_SHADE_LABELS, getTailwindShadeTokens, resolveTailwindColor, richTextEditorTheme };
|
|
@@ -48,6 +48,19 @@ export interface RichTextEditorProps extends Omit<React.HTMLAttributes<HTMLDivEl
|
|
|
48
48
|
toolbar?: ToolbarConfig;
|
|
49
49
|
/** Component-level theme overrides */
|
|
50
50
|
theme?: RichTextEditorThemeOverrides;
|
|
51
|
+
/**
|
|
52
|
+
* Custom list of font families shown by the `fontFamily` toolbar tool.
|
|
53
|
+
* If omitted, ships with a curated default set (system Default + 8 Google Fonts).
|
|
54
|
+
* Provide your own list when you self-host fonts or want a custom curation.
|
|
55
|
+
*/
|
|
56
|
+
fontFamilies?: FontFamilyOption[];
|
|
57
|
+
/**
|
|
58
|
+
* Whether the editor should lazy-load Google Fonts when picked.
|
|
59
|
+
* Defaults to `true`. Set to `false` if you load fonts yourself
|
|
60
|
+
* (e.g. via `next/font` or a `<link>` in your app head) — the picker still
|
|
61
|
+
* applies the font, but no network request is fired.
|
|
62
|
+
*/
|
|
63
|
+
loadFontsOnDemand?: boolean;
|
|
51
64
|
/**
|
|
52
65
|
* Optional HTML sanitizer function applied before setting innerHTML.
|
|
53
66
|
* Receives raw HTML string, must return sanitized HTML string.
|
|
@@ -78,8 +91,27 @@ export interface ToolbarConfig {
|
|
|
78
91
|
/**
|
|
79
92
|
* Available toolbar tools
|
|
80
93
|
*/
|
|
81
|
-
export type ToolbarTool = 'bold' | 'italic' | 'underline' | 'fontSize' | 'textColor' | 'alignLeft' | 'alignCenter' | 'alignRight' | 'undo' | 'redo' | 'separator';
|
|
82
|
-
|
|
94
|
+
export type ToolbarTool = 'bold' | 'italic' | 'underline' | 'fontWeight' | 'fontFamily' | 'fontSize' | 'lineHeight' | 'letterSpacing' | 'textColor' | 'alignLeft' | 'alignCenter' | 'alignRight' | 'undo' | 'redo' | 'separator';
|
|
95
|
+
/**
|
|
96
|
+
* Font family option used by the RichTextEditor font picker.
|
|
97
|
+
* - `key` is the stable identifier matched against the current selection.
|
|
98
|
+
* - `family` is the canonical Google Fonts family name (used to build the load URL).
|
|
99
|
+
* Omit for system fonts (e.g. "Default" or "Sans") — they will not be lazy-loaded.
|
|
100
|
+
* - `stack` is the CSS font-family value applied to the selection. Always include
|
|
101
|
+
* safe fallbacks so text remains readable while the font is loading.
|
|
102
|
+
* - `weights` is the optional list of weights to request (defaults to all 9).
|
|
103
|
+
*/
|
|
104
|
+
export interface FontFamilyOption {
|
|
105
|
+
key: string;
|
|
106
|
+
label: string;
|
|
107
|
+
stack: string;
|
|
108
|
+
family?: string;
|
|
109
|
+
weights?: number[];
|
|
110
|
+
}
|
|
111
|
+
export type RichTextFontSizeKey = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl' | '8xl' | '9xl';
|
|
112
|
+
export type RichTextFontWeightKey = 'thin' | 'extralight' | 'light' | 'normal' | 'medium' | 'semibold' | 'bold' | 'extrabold' | 'black';
|
|
113
|
+
export type RichTextLineHeightKey = 'tight' | 'snug' | 'normal' | 'relaxed' | 'loose';
|
|
114
|
+
export type RichTextLetterSpacingKey = 'tighter' | 'tight' | 'normal' | 'wide' | 'wider' | 'widest';
|
|
83
115
|
/**
|
|
84
116
|
* Text formatting state
|
|
85
117
|
*/
|
|
@@ -89,6 +121,10 @@ export interface FormattingState {
|
|
|
89
121
|
underline: boolean;
|
|
90
122
|
textAlign: 'left' | 'center' | 'right' | 'justify';
|
|
91
123
|
fontSize: RichTextFontSizeKey;
|
|
124
|
+
fontWeight: RichTextFontWeightKey;
|
|
125
|
+
fontFamily: string;
|
|
126
|
+
lineHeight: RichTextLineHeightKey;
|
|
127
|
+
letterSpacing: RichTextLetterSpacingKey;
|
|
92
128
|
textColor: string;
|
|
93
129
|
}
|
|
94
130
|
/**
|
|
@@ -109,8 +145,10 @@ export interface RichTextEditorThemeOverrides {
|
|
|
109
145
|
containerStyle?: string;
|
|
110
146
|
/** ContentEditable element style */
|
|
111
147
|
editorStyle?: string;
|
|
112
|
-
/** Toolbar container style */
|
|
148
|
+
/** Toolbar container style (docked variant) */
|
|
113
149
|
toolbarStyle?: string;
|
|
150
|
+
/** Floating toolbar container style (selection-anchored variant) */
|
|
151
|
+
floatingToolbarStyle?: string;
|
|
114
152
|
/** Toolbar button style */
|
|
115
153
|
toolbarButtonStyle?: string;
|
|
116
154
|
/** Size variants */
|
|
@@ -132,6 +170,7 @@ export interface RichTextEditorTheme {
|
|
|
132
170
|
containerStyle: string;
|
|
133
171
|
editorStyle: string;
|
|
134
172
|
toolbarStyle: string;
|
|
173
|
+
floatingToolbarStyle: string;
|
|
135
174
|
toolbarButtonStyle: string;
|
|
136
175
|
dropdownStyle: string;
|
|
137
176
|
dropdownItemStyle: string;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { RichTextEditor } from './RichTextEditor';
|
|
2
|
-
export type { RichTextEditorProps, RichTextEditorSize, RichTextEditorState, ToolbarConfig, ToolbarTool, FormattingState, ColorOption, RichTextEditorTheme, RichTextEditorThemeOverrides, } from './RichTextEditor.types';
|
|
1
|
+
export { RichTextEditor, DEFAULT_FONT_FAMILY_OPTIONS, loadGoogleFont, } from './RichTextEditor';
|
|
2
|
+
export type { RichTextEditorProps, RichTextEditorSize, RichTextEditorState, ToolbarConfig, ToolbarTool, FormattingState, FontFamilyOption, ColorOption, RichTextEditorTheme, RichTextEditorThemeOverrides, } from './RichTextEditor.types';
|
|
3
3
|
export { richTextEditorTheme, colorOptions } from './RichTextEditor.theme';
|
|
@@ -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
|
-
"
|
|
99
|
+
"shadow-[inset_0_0_0_2px_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
|
};
|
|
@@ -10,7 +10,7 @@ const sliderTheme = {
|
|
|
10
10
|
// Root container with layout
|
|
11
11
|
rootStyle: "relative flex items-center w-full touch-none select-none data-[orientation=vertical]:flex-col data-[orientation=vertical]:h-full",
|
|
12
12
|
// Track (background)
|
|
13
|
-
trackStyle: "relative w-full h-2 grow rounded-full bg-[var(--color-
|
|
13
|
+
trackStyle: "relative w-full h-2 grow rounded-full bg-[var(--color-surface-sunken)] overflow-hidden data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[orientation=vertical]:w-2 data-[orientation=vertical]:h-full shadow-inner",
|
|
14
14
|
// Range (filled portion) - rounded to match track clipping
|
|
15
15
|
rangeStyle: "absolute h-full bg-gradient-to-r from-[var(--color-primary-500)] to-[var(--color-primary-700)] transition-all rounded-full data-[disabled]:bg-[var(--color-background-disabled)] data-[invalid]:bg-[var(--color-danger)]",
|
|
16
16
|
// Thumb (draggable handle)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
const switchTheme = {
|
|
5
5
|
container: "flex w-full justify-between items-center gap-4",
|
|
6
|
-
track: "rounded-full cursor-pointer shadow-inner bg-[var(--color-
|
|
6
|
+
track: "rounded-full cursor-pointer shadow-inner bg-[var(--color-surface-sunken)] data-[state=checked]:bg-[var(--color-primary)] data-[state=disabled]:bg-[var(--color-background-disabled)] data-[state=disabled]:cursor-not-allowed data-[state=invalid]:border-2 data-[state=invalid]:border-[var(--color-danger)] outline outline-[var(--color-border)] transition-colors duration-300",
|
|
7
7
|
thumb: "rounded-full bg-transparent overflow-hidden border border-[var(--color-border)]/40 shadow-lg",
|
|
8
8
|
description: "text-sm text-[var(--color-text-muted)] -mt-1.5",
|
|
9
9
|
trackSizes: {
|
|
@@ -78,8 +78,8 @@ const timePickerTheme = {
|
|
|
78
78
|
"dark:text-[var(--color-neutral-200)] dark:placeholder:text-[var(--color-neutral-500)]",
|
|
79
79
|
// AM/PM period toggle button
|
|
80
80
|
periodToggleStyle: "px-1.5 py-0.5 text-xs font-semibold rounded " +
|
|
81
|
-
"bg-[var(--color-
|
|
82
|
-
"hover:bg-[var(--color-
|
|
81
|
+
"bg-[var(--color-surface-sunken)] text-[var(--color-text-primary)] " +
|
|
82
|
+
"hover:bg-[var(--color-surface-hover)] transition-colors cursor-pointer select-none " +
|
|
83
83
|
"dark:bg-[var(--color-neutral-700)] dark:text-[var(--color-neutral-200)] " +
|
|
84
84
|
"dark:hover:bg-[var(--color-neutral-600)]",
|
|
85
85
|
};
|
|
@@ -92,6 +92,7 @@ import '../../core/ContextMenu/ContextMenu.js';
|
|
|
92
92
|
import '../../core/ContextMenu/ContextMenu.theme.js';
|
|
93
93
|
import '../../core/Pill/Pill.js';
|
|
94
94
|
import '../../core/Icon/Icon.js';
|
|
95
|
+
import '../../core/ImagePlaceholder/ImagePlaceholder.js';
|
|
95
96
|
import { useIsClient } from '../../../hooks/useIsClient.js';
|
|
96
97
|
import { useDarkMode } from '../../../hooks/useDarkMode.js';
|
|
97
98
|
|
|
@@ -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]) || "
|
|
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"
|
|
29
29
|
: "";
|
|
30
30
|
// Determine whether start icon is present (for input padding)
|
|
31
31
|
const hasStartIcon = iconStart !== undefined ? Boolean(iconStart) : true;
|
|
@@ -8,12 +8,12 @@ const formsBaseTheme = {
|
|
|
8
8
|
// Common wrapper style
|
|
9
9
|
wrapperStyle: "relative w-full",
|
|
10
10
|
// Common input group style with focus, hover, and state variations
|
|
11
|
-
inputGroupBaseStyle: "relative flex rounded-[var(--form-radius)] outline
|
|
12
|
-
"focus-within:
|
|
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
13
|
"focus-within:ring-4 focus-within:ring-[var(--color-primary)]/10 bg-white transition-all " +
|
|
14
14
|
// Dark mode
|
|
15
|
-
"dark:bg-[var(--color-neutral-900)] dark:
|
|
16
|
-
"dark:focus-within:
|
|
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",
|
|
17
17
|
// Common base input/control style
|
|
18
18
|
controlBaseStyle: "w-full bg-transparent text-sm text-[var(--color-text-primary)] " +
|
|
19
19
|
"placeholder:text-[var(--color-text-placeholder)] focus:outline-none " +
|
|
@@ -44,7 +44,7 @@ const formsBaseTheme = {
|
|
|
44
44
|
// Common state variants
|
|
45
45
|
states: {
|
|
46
46
|
default: "",
|
|
47
|
-
disabled: "cursor-not-allowed bg-[var(--color-background-disabled)]
|
|
47
|
+
disabled: "cursor-not-allowed bg-[var(--color-background-disabled)] shadow-[inset_0_0_0_1px_var(--color-border)] " +
|
|
48
48
|
"[&_input]:text-[var(--color-text-disabled)] [&_textarea]:text-[var(--color-text-disabled)] " +
|
|
49
49
|
"[&_select]:text-[var(--color-text-disabled)] [&_input]:cursor-not-allowed " +
|
|
50
50
|
"[&_textarea]:cursor-not-allowed [&_select]:cursor-not-allowed " +
|
|
@@ -52,17 +52,17 @@ const formsBaseTheme = {
|
|
|
52
52
|
"[&_textarea]:placeholder:text-[var(--color-text-placeholder)] " +
|
|
53
53
|
"[&_select]:placeholder:text-[var(--color-text-placeholder)] [&_button]:cursor-not-allowed " +
|
|
54
54
|
// Dark mode
|
|
55
|
-
"dark:bg-[var(--color-neutral-800)] dark:
|
|
56
|
-
invalid: "
|
|
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
57
|
// Dark mode
|
|
58
|
-
"dark:bg-[var(--color-danger-950)]/30 dark:
|
|
58
|
+
"dark:bg-[var(--color-danger-950)]/30 dark:shadow-[inset_0_0_0_1px_var(--color-danger-500)]",
|
|
59
59
|
},
|
|
60
60
|
// Common focus state variants
|
|
61
61
|
focusStates: {
|
|
62
|
-
default: "
|
|
63
|
-
"dark:
|
|
64
|
-
disabled: "
|
|
65
|
-
invalid: "
|
|
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",
|
|
64
|
+
disabled: "shadow-none",
|
|
65
|
+
invalid: "shadow-[inset_0_0_0_2px_var(--color-danger-500)] ring-4 ring-[var(--color-danger-500)]/10 " +
|
|
66
66
|
"dark:ring-[var(--color-danger-500)]/20",
|
|
67
67
|
},
|
|
68
68
|
// Common hover state variants
|
|
@@ -114,6 +114,7 @@ import '../core/ContextMenu/ContextMenu.js';
|
|
|
114
114
|
import '../core/ContextMenu/ContextMenu.theme.js';
|
|
115
115
|
import '../core/Pill/Pill.js';
|
|
116
116
|
import '../core/Icon/Icon.js';
|
|
117
|
+
import '../core/ImagePlaceholder/ImagePlaceholder.js';
|
|
117
118
|
import './TimePicker/WheelColumn.js';
|
|
118
119
|
export { timePickerTheme } from './TimePicker/TimePicker.theme.js';
|
|
119
120
|
export { Slider } from './Slider/Slider.js';
|
|
@@ -77,7 +77,6 @@ import '../../core/Sidebar/SidebarContent.js';
|
|
|
77
77
|
import '../../core/Sidebar/SidebarFooter.js';
|
|
78
78
|
import '../../core/Sidebar/SidebarNav.js';
|
|
79
79
|
import '../../core/Sidebar/SidebarNavGroup.js';
|
|
80
|
-
import 'motion/react';
|
|
81
80
|
import '../../core/Sidebar/SidebarToggle.js';
|
|
82
81
|
import '../../core/Sidebar/SidebarMobileTrigger.js';
|
|
83
82
|
import '../../core/Sidebar/SidebarUserProfile.js';
|
|
@@ -88,6 +87,7 @@ import '../../core/ContextMenu/ContextMenu.js';
|
|
|
88
87
|
import '../../core/ContextMenu/ContextMenu.theme.js';
|
|
89
88
|
import '../../core/Pill/Pill.js';
|
|
90
89
|
import '../../core/Icon/Icon.js';
|
|
90
|
+
import '../../core/ImagePlaceholder/ImagePlaceholder.js';
|
|
91
91
|
import { formLayoutTheme } from './FormLayout.theme.js';
|
|
92
92
|
import { FormLayoutSection } from './FormLayoutSection.js';
|
|
93
93
|
import { FormLayoutFooter } from './FormLayoutFooter.js';
|
|
@@ -95,13 +95,15 @@ import { FormLayoutFooter } from './FormLayoutFooter.js';
|
|
|
95
95
|
const isFooter = (child) => React__default.isValidElement(child) && child.type === FormLayoutFooter;
|
|
96
96
|
const FormLayoutRoot = React__default.forwardRef(({ className, theme: customTheme, children, ...props }, ref) => {
|
|
97
97
|
const theme = { ...formLayoutTheme, ...customTheme };
|
|
98
|
-
// Inject <Separator /> between any adjacent children, unless one of them is Footer
|
|
99
|
-
// (Footer already has border-t, so no separator needed before it)
|
|
98
|
+
// Inject <Separator /> between any adjacent children, unless one of them is Footer.
|
|
100
99
|
const childArray = React__default.Children.toArray(children).filter(Boolean);
|
|
101
100
|
const rendered = childArray.map((child, index) => {
|
|
102
101
|
const prev = childArray[index - 1];
|
|
103
102
|
const needsSeparator = index > 0 && !isFooter(child) && !isFooter(prev);
|
|
104
|
-
|
|
103
|
+
const childKey = React__default.isValidElement(child) && child.key != null
|
|
104
|
+
? child.key
|
|
105
|
+
: `form-layout-child-${index}`;
|
|
106
|
+
return (jsxs(React__default.Fragment, { children: [needsSeparator && jsx(Separator, {}), child] }, childKey));
|
|
105
107
|
});
|
|
106
108
|
return (jsx("div", { ref: ref, className: cn(theme.root, className), ...props, children: rendered }));
|
|
107
109
|
});
|
|
@@ -25,11 +25,11 @@ export interface FormLayoutProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
25
25
|
/** Theme overrides for the root container. */
|
|
26
26
|
theme?: FormLayoutThemeOverrides;
|
|
27
27
|
}
|
|
28
|
-
export interface FormLayoutSectionProps extends React.HTMLAttributes<HTMLElement> {
|
|
28
|
+
export interface FormLayoutSectionProps extends Omit<React.HTMLAttributes<HTMLElement>, "title"> {
|
|
29
29
|
/** Optional section title. If omitted along with subtitle and action, the sidebar column is hidden. */
|
|
30
|
-
title?:
|
|
30
|
+
title?: React.ReactNode;
|
|
31
31
|
/** Optional subtitle displayed below the title. */
|
|
32
|
-
subtitle?:
|
|
32
|
+
subtitle?: React.ReactNode;
|
|
33
33
|
/** Optional action element rendered below the subtitle. */
|
|
34
34
|
action?: React.ReactNode;
|
|
35
35
|
/** Additional className applied to the content area. */
|
|
@@ -4,9 +4,14 @@ import { cn } from '../../../utils/cn.js';
|
|
|
4
4
|
import { formLayoutTheme } from './FormLayout.theme.js';
|
|
5
5
|
|
|
6
6
|
const FormLayoutSection = React__default.forwardRef(({ title, subtitle, action, className, contentClassName, theme: customTheme, children, ...props }, ref) => {
|
|
7
|
+
var _a;
|
|
7
8
|
const theme = { ...formLayoutTheme, ...customTheme };
|
|
8
9
|
const hasSidebar = !!(title || subtitle || action);
|
|
9
|
-
|
|
10
|
+
const generatedTitleId = React__default.useId();
|
|
11
|
+
const titleId = title
|
|
12
|
+
? (_a = props["aria-labelledby"]) !== null && _a !== void 0 ? _a : generatedTitleId
|
|
13
|
+
: props["aria-labelledby"];
|
|
14
|
+
return (jsxs("section", { ref: ref, className: cn(theme.section, className), "aria-labelledby": titleId, ...props, children: [hasSidebar && (jsxs("div", { className: theme.sectionSidebar, children: [title && (jsx("h2", { id: titleId, className: theme.sectionTitle, children: title })), subtitle && (jsx("div", { className: theme.sectionSubtitle, children: subtitle })), action && jsx("div", { className: theme.sectionAction, children: action })] })), jsx("div", { className: cn(hasSidebar ? theme.sectionContent : theme.sectionContentFull, contentClassName), children: children })] }));
|
|
10
15
|
});
|
|
11
16
|
FormLayoutSection.displayName = "FormLayout.Section";
|
|
12
17
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import type { PageLayoutProps } from "./PageLayout.types";
|
|
2
|
+
import type { PageLayoutContentProps, PageLayoutProps } from "./PageLayout.types";
|
|
3
3
|
export declare const PageLayout: React.ForwardRefExoticComponent<PageLayoutProps & React.RefAttributes<HTMLDivElement>> & {
|
|
4
4
|
Sidebar: React.ForwardRefExoticComponent<import("./PageLayout.types").PageLayoutSidebarProps & React.RefAttributes<HTMLElement>>;
|
|
5
5
|
Header: React.ForwardRefExoticComponent<import("./PageLayout.types").PageLayoutHeaderProps & React.RefAttributes<HTMLElement>>;
|
|
6
|
-
Content: React.ForwardRefExoticComponent<
|
|
6
|
+
Content: React.ForwardRefExoticComponent<PageLayoutContentProps & React.RefAttributes<HTMLElement>>;
|
|
7
7
|
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import React__default from 'react';
|
|
3
3
|
import { cn } from '../../../utils/cn.js';
|
|
4
|
-
import {
|
|
4
|
+
import { getPageLayoutTheme } from './PageLayout.theme.js';
|
|
5
5
|
import { PageLayoutSidebar } from './PageLayoutSidebar.js';
|
|
6
6
|
import { PageLayoutHeader } from './PageLayoutHeader.js';
|
|
7
7
|
import { PageLayoutContent } from './PageLayoutContent.js';
|
|
8
8
|
|
|
9
|
-
const PageLayoutRoot = React__default.forwardRef(({ className, theme: customTheme, children, ...props }, ref) => {
|
|
10
|
-
const theme =
|
|
9
|
+
const PageLayoutRoot = React__default.forwardRef(({ className, theme: customTheme, variant = "auto", contentWidth = "full", contentPadding = "md", children, ...props }, ref) => {
|
|
10
|
+
const theme = getPageLayoutTheme(customTheme);
|
|
11
11
|
// Separate Sidebar children from the rest (Header, Content)
|
|
12
12
|
// so we can wrap non-sidebar children in a vertical main column.
|
|
13
13
|
const childArray = React__default.Children.toArray(children);
|
|
@@ -21,7 +21,25 @@ const PageLayoutRoot = React__default.forwardRef(({ className, theme: customThem
|
|
|
21
21
|
main.push(child);
|
|
22
22
|
}
|
|
23
23
|
});
|
|
24
|
-
|
|
24
|
+
const resolvedVariant = variant === "auto"
|
|
25
|
+
? sidebar.length > 0
|
|
26
|
+
? "sidebar"
|
|
27
|
+
: "topbar"
|
|
28
|
+
: variant;
|
|
29
|
+
const mainChildren = main.map((child) => {
|
|
30
|
+
var _a, _b;
|
|
31
|
+
if (React__default.isValidElement(child) &&
|
|
32
|
+
child.type === PageLayoutContent) {
|
|
33
|
+
return React__default.cloneElement(child, {
|
|
34
|
+
contentWidth: (_a = child.props.contentWidth) !== null && _a !== void 0 ? _a : contentWidth,
|
|
35
|
+
contentPadding: (_b = child.props.contentPadding) !== null && _b !== void 0 ? _b : contentPadding,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return child;
|
|
39
|
+
});
|
|
40
|
+
return (jsx("div", { ref: ref, className: cn(theme.root, className), ...props, children: jsxs("div", { className: cn(theme.shell, resolvedVariant === "sidebar"
|
|
41
|
+
? theme.sidebarLayout
|
|
42
|
+
: theme.topbarLayout), children: [resolvedVariant === "sidebar" && sidebar, jsx("div", { className: cn(theme.main), children: mainChildren })] }) }));
|
|
25
43
|
});
|
|
26
44
|
PageLayoutRoot.displayName = "PageLayout";
|
|
27
45
|
const PageLayout = Object.assign(PageLayoutRoot, {
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import type { PageLayoutTheme } from "./PageLayout.types";
|
|
1
|
+
import type { PageLayoutTheme, PageLayoutThemeOverrides } from "./PageLayout.types";
|
|
2
2
|
export declare const pageLayoutTheme: PageLayoutTheme;
|
|
3
|
+
export declare const getPageLayoutTheme: (customTheme?: PageLayoutThemeOverrides) => PageLayoutTheme;
|
|
@@ -1,10 +1,39 @@
|
|
|
1
1
|
const pageLayoutTheme = {
|
|
2
|
-
root: "
|
|
3
|
-
|
|
2
|
+
root: "min-h-screen overflow-hidden bg-white text-[var(--color-text-primary)]",
|
|
3
|
+
shell: "h-full min-h-[inherit] min-w-0",
|
|
4
|
+
sidebarLayout: "flex",
|
|
5
|
+
topbarLayout: "flex flex-col",
|
|
6
|
+
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",
|
|
7
|
+
sidebarScroll: "min-h-0 flex-1",
|
|
4
8
|
sidebarCollapsed: "hidden lg:flex",
|
|
5
|
-
main: "flex flex-col flex-1 min-w-0 overflow-hidden",
|
|
6
|
-
header: "shrink-0 border-b border-[var(--color-border)] bg-[var(--color-background)]",
|
|
7
|
-
content: "flex-1
|
|
9
|
+
main: "flex flex-col flex-1 min-h-0 min-w-0 overflow-hidden",
|
|
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
|
+
content: "flex flex-1 min-h-0 min-w-0",
|
|
12
|
+
contentScroll: "min-h-0 flex-1",
|
|
13
|
+
contentInner: "mx-auto w-full",
|
|
14
|
+
contentPadding: {
|
|
15
|
+
none: "p-0",
|
|
16
|
+
sm: "p-3 sm:p-4",
|
|
17
|
+
md: "p-4 sm:p-6 lg:p-8",
|
|
18
|
+
lg: "p-5 sm:p-8 lg:p-10",
|
|
19
|
+
},
|
|
20
|
+
contentWidth: {
|
|
21
|
+
full: "max-w-none",
|
|
22
|
+
wide: "max-w-7xl",
|
|
23
|
+
contained: "max-w-5xl",
|
|
24
|
+
},
|
|
8
25
|
};
|
|
26
|
+
const getPageLayoutTheme = (customTheme) => ({
|
|
27
|
+
...pageLayoutTheme,
|
|
28
|
+
...customTheme,
|
|
29
|
+
contentPadding: {
|
|
30
|
+
...pageLayoutTheme.contentPadding,
|
|
31
|
+
...customTheme === null || customTheme === void 0 ? void 0 : customTheme.contentPadding,
|
|
32
|
+
},
|
|
33
|
+
contentWidth: {
|
|
34
|
+
...pageLayoutTheme.contentWidth,
|
|
35
|
+
...customTheme === null || customTheme === void 0 ? void 0 : customTheme.contentWidth,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
9
38
|
|
|
10
|
-
export { pageLayoutTheme };
|
|
39
|
+
export { getPageLayoutTheme, pageLayoutTheme };
|