@nordmanai/nif 0.1.0 → 0.2.1
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/README.md +18 -0
- package/bin/nif.mjs +196 -0
- package/dist/index.d.ts +30 -1
- package/dist/index.js +9661 -2499
- package/dist/styles.css +1 -1
- package/dist/tokens.css +4 -1
- package/dist/ui/components/nm-ai/nm-ai.d.ts +7 -7
- package/dist/ui/components/nm-brand-logo/nm-brand-logo.d.ts +10 -0
- package/dist/ui/components/nm-breadcrumb/nm-breadcrumb.d.ts +11 -0
- package/dist/ui/components/nm-button/nm-button.d.ts +2 -0
- package/dist/ui/components/nm-button-group/nm-button-group.d.ts +17 -0
- package/dist/ui/components/nm-calendar/nm-calendar.d.ts +3 -0
- package/dist/ui/components/nm-card/nm-card.d.ts +34 -0
- package/dist/ui/components/nm-chip/nm-chip.d.ts +38 -0
- package/dist/ui/components/nm-code-block/nm-code-block.d.ts +55 -0
- package/dist/ui/components/nm-color-picker/nm-color-picker.d.ts +15 -0
- package/dist/ui/components/nm-combobox/nm-combobox.d.ts +26 -0
- package/dist/ui/components/nm-command/nm-command.d.ts +37 -0
- package/dist/ui/components/nm-composer/nm-composer.d.ts +4 -0
- package/dist/ui/components/nm-context-menu/nm-context-menu.d.ts +9 -0
- package/dist/ui/components/nm-date-picker/nm-date-picker.d.ts +35 -0
- package/dist/ui/components/nm-dialog/nm-dialog.d.ts +13 -0
- package/dist/ui/components/nm-field/nm-field.d.ts +2 -0
- package/dist/ui/components/nm-form-field/nm-form-field.d.ts +18 -0
- package/dist/ui/components/nm-gallery/nm-gallery.d.ts +8 -0
- package/dist/ui/components/nm-input/nm-input.d.ts +5 -0
- package/dist/ui/components/nm-input-group/nm-input-group.d.ts +9 -0
- package/dist/ui/components/nm-label/nm-label.d.ts +2 -0
- package/dist/ui/components/nm-menubar/nm-menubar.d.ts +9 -0
- package/dist/ui/components/nm-native-select/nm-native-select.d.ts +5 -0
- package/dist/ui/components/nm-panel/nm-panel.d.ts +14 -0
- package/dist/ui/components/nm-prose/nm-prose.d.ts +6 -0
- package/dist/ui/components/nm-resize-handle/nm-resize-handle.d.ts +18 -0
- package/dist/ui/components/nm-select/nm-select.d.ts +22 -0
- package/dist/ui/components/nm-side-panel/nm-side-panel.d.ts +33 -0
- package/dist/ui/components/nm-slider/nm-slider.d.ts +5 -1
- package/dist/ui/components/nm-status-bar/nm-status-bar.d.ts +8 -0
- package/dist/ui/components/nm-table/nm-table.d.ts +38 -0
- package/dist/ui/components/nm-textarea/nm-textarea.d.ts +2 -0
- package/dist/ui/components/nm-toolbar/nm-toolbar.d.ts +21 -0
- package/dist/ui/config/nm-ai.d.ts +0 -3
- package/dist/ui/config/nm-appearance.d.ts +36 -1
- package/dist/ui/config/nm-button.d.ts +2 -1
- package/dist/ui/config/nm-composer.d.ts +1 -2
- package/dist/ui/config/nm-field.d.ts +2 -0
- package/dist/ui/config/nm-icons.d.ts +13 -1
- package/dist/ui/config/nm-radius.d.ts +4 -4
- package/dist/ui/config/nm-side-panel.d.ts +33 -0
- package/dist/ui/lib/appearance/appearanceState.d.ts +1 -0
- package/dist/ui/lib/appearance/deriveTokens.d.ts +2 -0
- package/package.json +12 -4
- package/registry/index.json +1634 -0
- package/registry/tokens.css +72 -0
- package/registry/ui/components/nm-ai/nm-ai.css +358 -0
- package/registry/ui/components/nm-ai/nm-ai.tsx +632 -0
- package/registry/ui/components/nm-app-panel/nm-app-panel.css +169 -0
- package/registry/ui/components/nm-ask/nm-ask.css +277 -0
- package/registry/ui/components/nm-avatar/nm-avatar.css +85 -0
- package/registry/ui/components/nm-avatar/nm-avatar.tsx +30 -0
- package/registry/ui/components/nm-bar-overflow/nm-bar-overflow.css +43 -0
- package/registry/ui/components/nm-bar-overflow/nm-bar-overflow.tsx +61 -0
- package/registry/ui/components/nm-bar-overflow/use-bar-overflow.ts +92 -0
- package/registry/ui/components/nm-brand-logo/nm-brand-logo.css +20 -0
- package/registry/ui/components/nm-brand-logo/nm-brand-logo.tsx +21 -0
- package/registry/ui/components/nm-breadcrumb/nm-breadcrumb.css +57 -0
- package/registry/ui/components/nm-breadcrumb/nm-breadcrumb.tsx +42 -0
- package/registry/ui/components/nm-button/nm-button.css +106 -0
- package/registry/ui/components/nm-button/nm-button.tsx +58 -0
- package/registry/ui/components/nm-button-group/nm-button-group.css +98 -0
- package/registry/ui/components/nm-button-group/nm-button-group.tsx +32 -0
- package/registry/ui/components/nm-calendar/nm-calendar.css +178 -0
- package/registry/ui/components/nm-calendar/nm-calendar.tsx +43 -0
- package/registry/ui/components/nm-card/nm-card.css +130 -0
- package/registry/ui/components/nm-card/nm-card.tsx +83 -0
- package/registry/ui/components/nm-chatbox/nm-chatbox-icon.tsx +39 -0
- package/registry/ui/components/nm-chatbox/nm-chatbox.css +682 -0
- package/registry/ui/components/nm-chatbox/nm-chatbox.tsx +101 -0
- package/registry/ui/components/nm-checkbox/nm-checkbox.css +61 -0
- package/registry/ui/components/nm-checkbox/nm-checkbox.tsx +14 -0
- package/registry/ui/components/nm-chip/nm-chip.css +112 -0
- package/registry/ui/components/nm-chip/nm-chip.tsx +86 -0
- package/registry/ui/components/nm-code-block/nm-code-block.css +240 -0
- package/registry/ui/components/nm-code-block/nm-code-block.tsx +196 -0
- package/registry/ui/components/nm-collection/nm-collection-bar.tsx +65 -0
- package/registry/ui/components/nm-collection/nm-collection-grid.tsx +69 -0
- package/registry/ui/components/nm-collection/nm-collection-query.tsx +99 -0
- package/registry/ui/components/nm-collection/nm-collection-row-menu.tsx +55 -0
- package/registry/ui/components/nm-collection/nm-collection-table.tsx +99 -0
- package/registry/ui/components/nm-collection/nm-collection-tile-actions.tsx +50 -0
- package/registry/ui/components/nm-collection/nm-collection-title.tsx +25 -0
- package/registry/ui/components/nm-collection/nm-collection.css +353 -0
- package/registry/ui/components/nm-collection/use-collection-scroll-reveal.ts +38 -0
- package/registry/ui/components/nm-color-picker/nm-color-picker.css +67 -0
- package/registry/ui/components/nm-color-picker/nm-color-picker.tsx +79 -0
- package/registry/ui/components/nm-combobox/nm-combobox.css +72 -0
- package/registry/ui/components/nm-combobox/nm-combobox.tsx +80 -0
- package/registry/ui/components/nm-command/nm-command.css +190 -0
- package/registry/ui/components/nm-command/nm-command.tsx +125 -0
- package/registry/ui/components/nm-composer/nm-composer.css +178 -0
- package/registry/ui/components/nm-composer/nm-composer.tsx +151 -0
- package/registry/ui/components/nm-context-menu/nm-context-menu.tsx +25 -0
- package/registry/ui/components/nm-date-picker/nm-date-picker.css +140 -0
- package/registry/ui/components/nm-date-picker/nm-date-picker.tsx +153 -0
- package/registry/ui/components/nm-dialog/nm-dialog.css +84 -0
- package/registry/ui/components/nm-dialog/nm-dialog.tsx +40 -0
- package/registry/ui/components/nm-dropdown/nm-dropdown-item.ts +68 -0
- package/registry/ui/components/nm-dropdown/nm-dropdown-options.tsx +242 -0
- package/registry/ui/components/nm-dropdown/nm-dropdown-panel.tsx +171 -0
- package/registry/ui/components/nm-dropdown/nm-dropdown-placement.ts +157 -0
- package/registry/ui/components/nm-dropdown/nm-dropdown.css +312 -0
- package/registry/ui/components/nm-dropdown/nm-dropdown.tsx +412 -0
- package/registry/ui/components/nm-dropdown-menu/nm-dropdown-menu.css +145 -0
- package/registry/ui/components/nm-dropdown-menu/nm-dropdown-menu.tsx +118 -0
- package/registry/ui/components/nm-field/nm-field.css +356 -0
- package/registry/ui/components/nm-field/nm-field.tsx +355 -0
- package/registry/ui/components/nm-form-field/nm-form-field.css +103 -0
- package/registry/ui/components/nm-form-field/nm-form-field.tsx +71 -0
- package/registry/ui/components/nm-gallery/nm-gallery.css +66 -0
- package/registry/ui/components/nm-gallery/nm-gallery.tsx +31 -0
- package/registry/ui/components/nm-hover-card/nm-hover-card.css +26 -0
- package/registry/ui/components/nm-hover-card/nm-hover-card.tsx +28 -0
- package/registry/ui/components/nm-icon/nm-icon.css +6 -0
- package/registry/ui/components/nm-icon/nm-icon.tsx +69 -0
- package/registry/ui/components/nm-icon/nm-lucide.tsx +180 -0
- package/registry/ui/components/nm-icon-border/nm-icon-border.tsx +56 -0
- package/registry/ui/components/nm-input/nm-input.css +75 -0
- package/registry/ui/components/nm-input/nm-input.tsx +7 -0
- package/registry/ui/components/nm-input-group/nm-input-group.css +66 -0
- package/registry/ui/components/nm-input-group/nm-input-group.tsx +20 -0
- package/registry/ui/components/nm-label/nm-label.css +11 -0
- package/registry/ui/components/nm-label/nm-label.tsx +6 -0
- package/registry/ui/components/nm-list-item/nm-list-item.css +177 -0
- package/registry/ui/components/nm-list-item/nm-list-item.tsx +112 -0
- package/registry/ui/components/nm-menubar/nm-menubar.css +32 -0
- package/registry/ui/components/nm-menubar/nm-menubar.tsx +19 -0
- package/registry/ui/components/nm-message/nm-message-actions.tsx +24 -0
- package/registry/ui/components/nm-message/nm-message-meta.tsx +49 -0
- package/registry/ui/components/nm-message/nm-message.css +686 -0
- package/registry/ui/components/nm-message/nm-text-shimmer.tsx +6 -0
- package/registry/ui/components/nm-message/nm-trace.tsx +219 -0
- package/registry/ui/components/nm-modal/nm-modal.css +763 -0
- package/registry/ui/components/nm-modal/nm-modal.tsx +497 -0
- package/registry/ui/components/nm-native-select/nm-native-select.css +47 -0
- package/registry/ui/components/nm-native-select/nm-native-select.tsx +23 -0
- package/registry/ui/components/nm-panel/nm-panel.css +73 -0
- package/registry/ui/components/nm-panel/nm-panel.tsx +35 -0
- package/registry/ui/components/nm-panel-bar/nm-panel-bar.css +20 -0
- package/registry/ui/components/nm-panel-bar/nm-panel-bar.tsx +48 -0
- package/registry/ui/components/nm-popover/nm-popover.css +43 -0
- package/registry/ui/components/nm-popover/nm-popover.tsx +40 -0
- package/registry/ui/components/nm-progress/nm-progress.css +21 -0
- package/registry/ui/components/nm-progress/nm-progress.tsx +14 -0
- package/registry/ui/components/nm-prose/nm-prose.css +81 -0
- package/registry/ui/components/nm-prose/nm-prose.tsx +10 -0
- package/registry/ui/components/nm-questionnaire/nm-questionnaire.css +182 -0
- package/registry/ui/components/nm-questionnaire/nm-questionnaire.tsx +221 -0
- package/registry/ui/components/nm-radio-group/nm-radio-group.css +48 -0
- package/registry/ui/components/nm-radio-group/nm-radio-group.tsx +15 -0
- package/registry/ui/components/nm-rail-icon/nm-rail-icon.css +6 -0
- package/registry/ui/components/nm-rail-icon/nm-rail-icon.tsx +28 -0
- package/registry/ui/components/nm-resize-handle/nm-resize-handle.css +45 -0
- package/registry/ui/components/nm-resize-handle/nm-resize-handle.tsx +102 -0
- package/registry/ui/components/nm-segmented/nm-segmented.css +104 -0
- package/registry/ui/components/nm-segmented/nm-segmented.tsx +77 -0
- package/registry/ui/components/nm-select/nm-select.css +78 -0
- package/registry/ui/components/nm-select/nm-select.tsx +64 -0
- package/registry/ui/components/nm-separator/nm-separator.css +14 -0
- package/registry/ui/components/nm-separator/nm-separator.tsx +6 -0
- package/registry/ui/components/nm-side-panel/nm-side-panel.css +93 -0
- package/registry/ui/components/nm-side-panel/nm-side-panel.tsx +86 -0
- package/registry/ui/components/nm-slider/nm-slider.css +53 -0
- package/registry/ui/components/nm-slider/nm-slider.tsx +40 -0
- package/registry/ui/components/nm-small-icon-button/nm-small-icon-button.tsx +66 -0
- package/registry/ui/components/nm-status-bar/nm-status-bar.css +50 -0
- package/registry/ui/components/nm-status-bar/nm-status-bar.tsx +28 -0
- package/registry/ui/components/nm-switch/nm-switch.css +45 -0
- package/registry/ui/components/nm-switch/nm-switch.tsx +10 -0
- package/registry/ui/components/nm-table/nm-table.css +155 -0
- package/registry/ui/components/nm-table/nm-table.tsx +95 -0
- package/registry/ui/components/nm-tabs/nm-tabs.css +28 -0
- package/registry/ui/components/nm-tabs/nm-tabs.tsx +32 -0
- package/registry/ui/components/nm-textarea/nm-textarea.css +41 -0
- package/registry/ui/components/nm-textarea/nm-textarea.tsx +6 -0
- package/registry/ui/components/nm-toggle/nm-toggle.css +55 -0
- package/registry/ui/components/nm-toggle/nm-toggle.tsx +16 -0
- package/registry/ui/components/nm-toolbar/nm-toolbar.css +42 -0
- package/registry/ui/components/nm-toolbar/nm-toolbar.tsx +54 -0
- package/registry/ui/components/nm-tooltip/nm-tooltip.css +37 -0
- package/registry/ui/components/nm-tooltip/nm-tooltip.tsx +35 -0
- package/registry/ui/components/nm-top-bar/nm-top-bar.css +29 -0
- package/registry/ui/components/nm-top-bar/nm-top-bar.tsx +34 -0
- package/registry/ui/components/nordman-icon-button/nordman-icon-button.css +119 -0
- package/registry/ui/components/nordman-icon-button/nordman-icon-button.tsx +185 -0
- package/registry/ui/components/nordman-login/nordman-login.css +195 -0
- package/registry/ui/components/nordman-login/nordman-login.tsx +136 -0
- package/registry/ui/components/nordman-login-field/nordman-login-field.tsx +55 -0
- package/registry/ui/components/nordman-login-forgot/nordman-login-forgot.tsx +56 -0
- package/registry/ui/components/nordman-login-google/nordman-login-google.tsx +28 -0
- package/registry/ui/components/nordman-login-hero/nordman-login-hero.tsx +38 -0
- package/registry/ui/components/nordman-login-register/nordman-login-register.tsx +70 -0
- package/registry/ui/components/nordman-login-reset/nordman-login-reset.tsx +71 -0
- package/registry/ui/components/nordman-login-reveal/nordman-login-reveal.tsx +41 -0
- package/registry/ui/components/nordman-login-sign-in/nordman-login-sign-in.tsx +69 -0
- package/registry/ui/components/nordman-toggle/nordman-toggle.css +28 -0
- package/registry/ui/components/nordman-toggle/nordman-toggle.tsx +35 -0
- package/registry/ui/config/nm-ai.ts +59 -0
- package/registry/ui/config/nm-appearance.ts +275 -0
- package/registry/ui/config/nm-bar-overflow.ts +10 -0
- package/registry/ui/config/nm-button.ts +38 -0
- package/registry/ui/config/nm-chatbox-icons.ts +67 -0
- package/registry/ui/config/nm-chatbox.ts +42 -0
- package/registry/ui/config/nm-collection.ts +101 -0
- package/registry/ui/config/nm-composer.ts +39 -0
- package/registry/ui/config/nm-dropdown.ts +62 -0
- package/registry/ui/config/nm-field.ts +43 -0
- package/registry/ui/config/nm-icon-button.ts +35 -0
- package/registry/ui/config/nm-icons.ts +417 -0
- package/registry/ui/config/nm-list-item.ts +14 -0
- package/registry/ui/config/nm-message.ts +106 -0
- package/registry/ui/config/nm-modal.ts +76 -0
- package/registry/ui/config/nm-panel-bar.ts +11 -0
- package/registry/ui/config/nm-questionnaire.ts +53 -0
- package/registry/ui/config/nm-radius.ts +56 -0
- package/registry/ui/config/nm-rail-icons.ts +27 -0
- package/registry/ui/config/nm-segmented.ts +19 -0
- package/registry/ui/config/nm-side-panel.ts +16 -0
- package/registry/ui/config/nm-site-palette.ts +30 -0
- package/registry/ui/config/nm-small-icon-button.ts +17 -0
- package/registry/ui/config/nm-tabs.ts +9 -0
- package/registry/ui/config/nm-top-bar.ts +4 -0
- package/registry/ui/config/nordman-chrome.ts +14 -0
- package/registry/ui/config/nordman-login.ts +28 -0
- package/registry/ui/content/nm-modal.ts +5 -0
- package/registry/ui/content/nordman-login.ts +85 -0
- package/registry/ui/kit-logger.ts +1 -0
- package/registry/ui/lib/appearance/appearanceState.ts +240 -0
- package/registry/ui/lib/appearance/applyAppearance.ts +36 -0
- package/registry/ui/lib/appearance/cloudOrbAppearance.ts +36 -0
- package/registry/ui/lib/appearance/color.ts +96 -0
- package/registry/ui/lib/appearance/deriveTokens.ts +218 -0
- package/registry/ui/lib/appearance/index.ts +6 -0
- package/registry/ui/lib/appearance/markTokens.ts +49 -0
- package/registry/ui/lib/appearance/readLayoutMetrics.ts +28 -0
- package/registry/ui/lib/bar-overflow.ts +41 -0
- package/registry/ui/lib/logger.ts +53 -0
- package/registry/ui/lib/menu-motion.ts +187 -0
- package/registry/ui/lib/nm-class.ts +4 -0
- package/registry/ui/lib/nordman-ui-locale.ts +43 -0
- package/registry/ui/styles/interface-theme.css +196 -0
- package/registry/ui/styles/light-appearance.css +72 -0
- package/registry/ui/styles/tokens.css +424 -0
- package/registry/ui/styles/utilities.css +12 -0
- package/dist/ui/components/nm-accordion/nm-accordion.d.ts +0 -6
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
.nm-radio-group {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
gap: var(--nm-space-12);
|
|
5
|
+
width: fit-content;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.nm-radio {
|
|
9
|
+
position: relative;
|
|
10
|
+
display: inline-flex;
|
|
11
|
+
flex-shrink: 0;
|
|
12
|
+
align-items: center;
|
|
13
|
+
justify-content: center;
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
width: var(--nm-icon-button);
|
|
16
|
+
height: var(--nm-icon-button);
|
|
17
|
+
padding: 0;
|
|
18
|
+
border: var(--nm-rule) solid var(--nm-stroke);
|
|
19
|
+
border-radius: 50%;
|
|
20
|
+
background: transparent;
|
|
21
|
+
cursor: pointer;
|
|
22
|
+
transition: border-color 0.15s;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.nm-radio:focus-visible {
|
|
26
|
+
outline: var(--nm-rule) solid var(--focus);
|
|
27
|
+
outline-offset: var(--nm-space-2);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.nm-radio[data-checked] {
|
|
31
|
+
border-color: var(--nm-fg);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.nm-radio[data-invalid] {
|
|
35
|
+
border-color: var(--nm-destructive);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.nm-radio[data-disabled] {
|
|
39
|
+
cursor: not-allowed;
|
|
40
|
+
opacity: 0.5;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.nm-radio__indicator {
|
|
44
|
+
width: 50%;
|
|
45
|
+
height: 50%;
|
|
46
|
+
border-radius: 50%;
|
|
47
|
+
background: var(--nm-fg);
|
|
48
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Radio as RadioPrimitive } from '@base-ui/react/radio';
|
|
2
|
+
import { RadioGroup as RadioGroupPrimitive } from '@base-ui/react/radio-group';
|
|
3
|
+
import { nmClass } from '../../lib/nm-class.ts';
|
|
4
|
+
|
|
5
|
+
export function NmRadioGroup({ className, ...props }: RadioGroupPrimitive.Props) {
|
|
6
|
+
return <RadioGroupPrimitive data-slot="radio-group" className={nmClass('nm-radio-group', className as string)} {...props} />;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function NmRadioGroupItem({ className, ...props }: RadioPrimitive.Root.Props) {
|
|
10
|
+
return (
|
|
11
|
+
<RadioPrimitive.Root data-slot="radio-group-item" className={nmClass('nm-radio', className as string)} {...props}>
|
|
12
|
+
<RadioPrimitive.Indicator data-slot="radio-group-indicator" className="nm-radio__indicator" />
|
|
13
|
+
</RadioPrimitive.Root>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { NmRailIconId } from '../../config/nm-rail-icons.ts';
|
|
3
|
+
import { NmLucide } from '../nm-icon/nm-lucide.tsx';
|
|
4
|
+
import { createLogger } from '../../kit-logger.ts';
|
|
5
|
+
|
|
6
|
+
const logger = createLogger('interface-nm-rail-icon');
|
|
7
|
+
|
|
8
|
+
const RAIL_LUCIDE: Record<NmRailIconId, string> = {
|
|
9
|
+
plus: 'plus',
|
|
10
|
+
plusSm: 'plus',
|
|
11
|
+
folder: 'folder',
|
|
12
|
+
chats: 'chat',
|
|
13
|
+
bot: 'bot',
|
|
14
|
+
app: 'app',
|
|
15
|
+
spreadsheet: 'monitor',
|
|
16
|
+
library: 'library',
|
|
17
|
+
settings: 'settings',
|
|
18
|
+
search: 'search',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type NmRailIconProps = {
|
|
22
|
+
id: NmRailIconId;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function NmRailIcon(props: NmRailIconProps): ReactNode {
|
|
26
|
+
logger.debug('render', props.id);
|
|
27
|
+
return <NmLucide id={RAIL_LUCIDE[props.id]} className="nm-rail-icon" />;
|
|
28
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
.nm-resize {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
width: var(--nm-space-6);
|
|
4
|
+
cursor: col-resize;
|
|
5
|
+
outline: none;
|
|
6
|
+
touch-action: none;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.nm-resize[data-placement='inside'] {
|
|
10
|
+
position: absolute;
|
|
11
|
+
z-index: 1;
|
|
12
|
+
top: 0;
|
|
13
|
+
bottom: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.nm-resize[data-placement='inside'][data-edge='start'] {
|
|
17
|
+
inset-inline-start: calc(var(--nm-space-6) / -2);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.nm-resize[data-placement='inside'][data-edge='end'] {
|
|
21
|
+
inset-inline-end: calc(var(--nm-space-6) / -2);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* The line is invisible until the Contrast setting raises it, and shows whenever the handle is in use. */
|
|
25
|
+
.nm-resize::after {
|
|
26
|
+
content: '';
|
|
27
|
+
position: absolute;
|
|
28
|
+
top: 0;
|
|
29
|
+
bottom: 0;
|
|
30
|
+
left: 50%;
|
|
31
|
+
width: var(--nm-space-2);
|
|
32
|
+
transform: translateX(-50%);
|
|
33
|
+
background: var(--nm-divider);
|
|
34
|
+
transition: background 0.12s;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.nm-resize:hover::after,
|
|
38
|
+
.nm-resize:focus-visible::after,
|
|
39
|
+
.nm-resize[data-dragging]::after {
|
|
40
|
+
background: var(--nm-stroke);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.nm-resize[data-dragging] {
|
|
44
|
+
user-select: none;
|
|
45
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { useEffect, useState, type KeyboardEvent, type PointerEvent, type RefObject } from 'react';
|
|
2
|
+
import { nmClass } from '../../lib/nm-class.ts';
|
|
3
|
+
|
|
4
|
+
const STEP = 16;
|
|
5
|
+
|
|
6
|
+
/** A length from the computed style of the target. A percentage is a share of its parent. */
|
|
7
|
+
function lengthOf(value: string, parentWidth: number, fallback: number): number {
|
|
8
|
+
if (value.endsWith('%')) {
|
|
9
|
+
return (parseFloat(value) / 100) * parentWidth;
|
|
10
|
+
}
|
|
11
|
+
const px = parseFloat(value);
|
|
12
|
+
return Number.isFinite(px) ? px : fallback;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The handle that resizes a panel. Every NIF panel that sits beside other content has one. It follows the pointer,
|
|
17
|
+
* the arrow keys, Home and End, and Enter or a double click restores the default width.
|
|
18
|
+
* The limits are the target's own `min-width` and `max-width`, so tokens in CSS decide how far it goes.
|
|
19
|
+
*/
|
|
20
|
+
export function NmResizeHandle({
|
|
21
|
+
target,
|
|
22
|
+
edge,
|
|
23
|
+
label,
|
|
24
|
+
onSize,
|
|
25
|
+
placement = 'free',
|
|
26
|
+
className,
|
|
27
|
+
}: {
|
|
28
|
+
/** The panel to resize. */
|
|
29
|
+
target: RefObject<HTMLElement | null>;
|
|
30
|
+
/** Which edge of the panel the handle is on. A panel on the right has its handle on the start edge. */
|
|
31
|
+
edge: 'start' | 'end';
|
|
32
|
+
label: string;
|
|
33
|
+
/** The new width in pixels, or null to restore the default. */
|
|
34
|
+
onSize: (px: number | null) => void;
|
|
35
|
+
/** `inside` pins the handle to the edge of its parent. `free` leaves placement to the layout. */
|
|
36
|
+
placement?: 'inside' | 'free';
|
|
37
|
+
className?: string;
|
|
38
|
+
}) {
|
|
39
|
+
const [dragging, setDragging] = useState(false);
|
|
40
|
+
const limits = () => {
|
|
41
|
+
const el = target.current;
|
|
42
|
+
if (!el) {
|
|
43
|
+
return { min: 0, max: 0, now: 0 };
|
|
44
|
+
}
|
|
45
|
+
const style = getComputedStyle(el);
|
|
46
|
+
const parent = el.parentElement?.getBoundingClientRect().width ?? 0;
|
|
47
|
+
return { min: lengthOf(style.minWidth, parent, 0), max: lengthOf(style.maxWidth, parent, parent), now: el.getBoundingClientRect().width };
|
|
48
|
+
};
|
|
49
|
+
const [shown, setShown] = useState(limits);
|
|
50
|
+
const refresh = () => setShown(limits());
|
|
51
|
+
useEffect(refresh, []);
|
|
52
|
+
const clamp = (px: number) => {
|
|
53
|
+
const { min, max } = limits();
|
|
54
|
+
return Math.min(max, Math.max(min, Math.round(px)));
|
|
55
|
+
};
|
|
56
|
+
const set = (px: number | null) => {
|
|
57
|
+
onSize(px);
|
|
58
|
+
requestAnimationFrame(refresh);
|
|
59
|
+
};
|
|
60
|
+
// The sign that grows the panel: dragging away from the panel, in reading direction.
|
|
61
|
+
const grows = edge === 'end' ? 1 : -1;
|
|
62
|
+
const onKeyDown = (event: KeyboardEvent) => {
|
|
63
|
+
const { min, max, now } = limits();
|
|
64
|
+
if (event.key === 'ArrowRight') set(clamp(now + grows * STEP));
|
|
65
|
+
else if (event.key === 'ArrowLeft') set(clamp(now - grows * STEP));
|
|
66
|
+
else if (event.key === 'Home') set(min);
|
|
67
|
+
else if (event.key === 'End') set(max);
|
|
68
|
+
else if (event.key === 'Enter') set(null);
|
|
69
|
+
else return;
|
|
70
|
+
event.preventDefault();
|
|
71
|
+
};
|
|
72
|
+
return (
|
|
73
|
+
<div
|
|
74
|
+
className={nmClass('nm-resize', className)}
|
|
75
|
+
data-slot="resize-handle"
|
|
76
|
+
data-edge={edge}
|
|
77
|
+
data-placement={placement}
|
|
78
|
+
data-dragging={dragging || undefined}
|
|
79
|
+
role="separator"
|
|
80
|
+
aria-orientation="vertical"
|
|
81
|
+
aria-label={label}
|
|
82
|
+
aria-valuemin={Math.round(shown.min)}
|
|
83
|
+
aria-valuemax={Math.round(shown.max)}
|
|
84
|
+
aria-valuenow={Math.round(shown.now)}
|
|
85
|
+
tabIndex={0}
|
|
86
|
+
onKeyDown={onKeyDown}
|
|
87
|
+
onDoubleClick={() => set(null)}
|
|
88
|
+
onPointerDown={(event: PointerEvent<HTMLDivElement>) => {
|
|
89
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
90
|
+
setDragging(true);
|
|
91
|
+
}}
|
|
92
|
+
onPointerMove={(event: PointerEvent<HTMLDivElement>) => {
|
|
93
|
+
const rect = target.current?.getBoundingClientRect();
|
|
94
|
+
if (dragging && rect) {
|
|
95
|
+
set(clamp(edge === 'end' ? event.clientX - rect.left : rect.right - event.clientX));
|
|
96
|
+
}
|
|
97
|
+
}}
|
|
98
|
+
onPointerUp={() => setDragging(false)}
|
|
99
|
+
onPointerCancel={() => setDragging(false)}
|
|
100
|
+
/>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
.nm-segmented {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
align-items: stretch;
|
|
4
|
+
gap: var(--nm-space-2);
|
|
5
|
+
padding: var(--toggle-pad);
|
|
6
|
+
border: var(--nm-rule) solid var(--nm-line-strong);
|
|
7
|
+
border-radius: var(--toggle-r);
|
|
8
|
+
background: transparent;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.nm-segmented__item {
|
|
12
|
+
display: inline-flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
border: 0;
|
|
16
|
+
font-family: var(--nm-font);
|
|
17
|
+
font-size: var(--control-fs);
|
|
18
|
+
font-weight: var(--nm-weight-regular);
|
|
19
|
+
cursor: pointer;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.nm-segmented__item:not(.nm-icon-button) {
|
|
23
|
+
gap: var(--nm-space-4);
|
|
24
|
+
box-sizing: border-box;
|
|
25
|
+
height: var(--toggle-h);
|
|
26
|
+
padding: 0 var(--toggle-px);
|
|
27
|
+
border-radius: var(--toggle-r);
|
|
28
|
+
background: transparent;
|
|
29
|
+
color: var(--nm-fg-subtle);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.nm-segmented__item:has(.nm-segmented__icon):not(.nm-icon-button) {
|
|
33
|
+
width: var(--toggle-h);
|
|
34
|
+
padding: 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.nm-segmented__item:not(.nm-icon-button):hover,
|
|
38
|
+
.nm-segmented__item:not(.nm-icon-button):focus-visible {
|
|
39
|
+
color: var(--nm-fg);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.nm-segmented--line .nm-segmented__item:not(.nm-icon-button)[data-active='true'] {
|
|
43
|
+
background: var(--nm-panel);
|
|
44
|
+
color: var(--nm-fg);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.nm-segmented--fill .nm-segmented__item:not(.nm-icon-button)[data-active='true'] {
|
|
48
|
+
background: var(--nm-fg);
|
|
49
|
+
color: var(--nm-canvas);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.nm-segmented__icon {
|
|
53
|
+
display: block;
|
|
54
|
+
width: var(--nm-icon-button);
|
|
55
|
+
height: var(--nm-icon-button);
|
|
56
|
+
flex-shrink: 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.nm-segmented--pills {
|
|
60
|
+
gap: var(--nm-space-8);
|
|
61
|
+
padding: 0;
|
|
62
|
+
border: 0;
|
|
63
|
+
border-radius: 0;
|
|
64
|
+
background: transparent;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.nm-segmented--pills .nm-segmented__item:not(.nm-icon-button),
|
|
68
|
+
.nm-segmented--pills .nm-segmented__item:has(.nm-segmented__icon):not(.nm-icon-button) {
|
|
69
|
+
width: auto;
|
|
70
|
+
height: var(--control-h);
|
|
71
|
+
gap: var(--control-gap);
|
|
72
|
+
padding: 0 var(--control-px);
|
|
73
|
+
border-radius: var(--nm-control-r);
|
|
74
|
+
background: transparent;
|
|
75
|
+
color: var(--nm-fg-subtle);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.nm-segmented--pills .nm-segmented__item:not(.nm-icon-button)[data-active='true'] {
|
|
79
|
+
background: var(--nm-panel);
|
|
80
|
+
color: var(--nm-fg);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.nm-segmented--pills .nm-segmented__item:not(.nm-icon-button):hover,
|
|
84
|
+
.nm-segmented--pills .nm-segmented__item:not(.nm-icon-button):focus-visible {
|
|
85
|
+
background: var(--nm-panel);
|
|
86
|
+
color: var(--nm-fg);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.nm-segmented--track {
|
|
90
|
+
display: flex;
|
|
91
|
+
width: 100%;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.nm-segmented--track .nm-segmented__item {
|
|
95
|
+
flex: 1 1 0;
|
|
96
|
+
background: transparent;
|
|
97
|
+
color: var(--nm-fg-subtle);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.nm-segmented--track .nm-segmented__item[data-active='true'] {
|
|
101
|
+
background: var(--nm-panel);
|
|
102
|
+
color: var(--nm-fg);
|
|
103
|
+
}
|
|
104
|
+
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { NmIconId } from '../../config/nm-icons.ts';
|
|
3
|
+
import {
|
|
4
|
+
NM_SEGMENTED_CLASSES,
|
|
5
|
+
NM_SEGMENTED_TONES,
|
|
6
|
+
type NmSegmentedTone,
|
|
7
|
+
} from '../../config/nm-segmented.ts';
|
|
8
|
+
import { NM_ICON_BUTTON_CLASSES, NM_ICON_BUTTON_TONES } from '../../config/nm-icon-button.ts';
|
|
9
|
+
import { createLogger } from '../../kit-logger.ts';
|
|
10
|
+
import { NmIcon } from '../nm-icon/nm-icon.tsx';
|
|
11
|
+
|
|
12
|
+
const logger = createLogger('interface-nm-segmented');
|
|
13
|
+
|
|
14
|
+
function segmentIcon(item: NmSegmentedItem): ReactNode {
|
|
15
|
+
if (item.imageSrc) {
|
|
16
|
+
return <img className={NM_SEGMENTED_CLASSES.icon} src={item.imageSrc} alt="" />;
|
|
17
|
+
}
|
|
18
|
+
if (item.icon) {
|
|
19
|
+
return <NmIcon id={item.icon} className={NM_SEGMENTED_CLASSES.icon} />;
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type NmSegmentedItem = {
|
|
25
|
+
id: string;
|
|
26
|
+
label: string;
|
|
27
|
+
icon?: NmIconId;
|
|
28
|
+
imageSrc?: string;
|
|
29
|
+
iconOnly?: boolean;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type NmSegmentedProps = {
|
|
33
|
+
items: readonly NmSegmentedItem[];
|
|
34
|
+
active: string;
|
|
35
|
+
tone?: NmSegmentedTone;
|
|
36
|
+
label: string;
|
|
37
|
+
testId?: string;
|
|
38
|
+
onSelect: (id: string) => void;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export function NmSegmented(props: NmSegmentedProps): ReactNode {
|
|
42
|
+
const tone = props.tone ?? NM_SEGMENTED_TONES.line;
|
|
43
|
+
logger.debug('render', props.active, { tone, items: props.items.length });
|
|
44
|
+
return (
|
|
45
|
+
<div
|
|
46
|
+
className={`${NM_SEGMENTED_CLASSES.root} ${NM_SEGMENTED_CLASSES[tone]}`}
|
|
47
|
+
role="radiogroup"
|
|
48
|
+
aria-label={props.label}
|
|
49
|
+
data-testid={props.testId}
|
|
50
|
+
>
|
|
51
|
+
{props.items.map((item) => {
|
|
52
|
+
const selected = item.id === props.active;
|
|
53
|
+
const iconOnly = item.iconOnly === true;
|
|
54
|
+
const className = iconOnly
|
|
55
|
+
? `${NM_SEGMENTED_CLASSES.item} ${NM_SEGMENTED_CLASSES.itemIcon} ${NM_ICON_BUTTON_CLASSES.root} ${NM_ICON_BUTTON_CLASSES[NM_ICON_BUTTON_TONES.subtle]}`
|
|
56
|
+
: NM_SEGMENTED_CLASSES.item;
|
|
57
|
+
return (
|
|
58
|
+
<button
|
|
59
|
+
key={item.id}
|
|
60
|
+
className={className}
|
|
61
|
+
type="button"
|
|
62
|
+
role="radio"
|
|
63
|
+
aria-label={iconOnly ? item.label : undefined}
|
|
64
|
+
aria-checked={selected}
|
|
65
|
+
data-active={selected ? 'true' : 'false'}
|
|
66
|
+
onClick={() => props.onSelect(item.id)}
|
|
67
|
+
>
|
|
68
|
+
{segmentIcon(item)}
|
|
69
|
+
{iconOnly ? null : item.label}
|
|
70
|
+
</button>
|
|
71
|
+
);
|
|
72
|
+
})}
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { NM_SEGMENTED_TONES };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
.nm-select__trigger {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
display: flex;
|
|
4
|
+
align-items: center;
|
|
5
|
+
gap: var(--nm-space-8);
|
|
6
|
+
width: 100%;
|
|
7
|
+
min-width: 0;
|
|
8
|
+
height: var(--nm-field-h);
|
|
9
|
+
padding: 0 var(--control-px);
|
|
10
|
+
border: var(--nm-rule) solid var(--nm-line-strong);
|
|
11
|
+
border-radius: var(--nm-control-r);
|
|
12
|
+
background: var(--nm-raised);
|
|
13
|
+
color: var(--nm-fg);
|
|
14
|
+
font: inherit;
|
|
15
|
+
font-size: var(--control-fs);
|
|
16
|
+
text-align: start;
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.nm-select__trigger[data-bare] {
|
|
21
|
+
height: auto;
|
|
22
|
+
padding: 0;
|
|
23
|
+
border: 0;
|
|
24
|
+
background: transparent;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.nm-select__trigger:hover,
|
|
28
|
+
.nm-select__trigger[data-popup-open],
|
|
29
|
+
.nm-select__trigger:focus-visible {
|
|
30
|
+
border-color: var(--nm-stroke);
|
|
31
|
+
outline: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.nm-select__trigger[data-disabled] {
|
|
35
|
+
opacity: 0.5;
|
|
36
|
+
cursor: not-allowed;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.nm-select__trigger > :first-child {
|
|
40
|
+
flex: 1;
|
|
41
|
+
min-width: 0;
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
text-overflow: ellipsis;
|
|
44
|
+
white-space: nowrap;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.nm-select__icon {
|
|
48
|
+
display: inline-flex;
|
|
49
|
+
flex-shrink: 0;
|
|
50
|
+
color: var(--nm-fg-subtle);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.nm-select__popup {
|
|
54
|
+
min-width: var(--anchor-width);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.nm-select__list {
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
gap: var(--nm-space-2);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.nm-select__item {
|
|
64
|
+
justify-content: space-between;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.nm-select__text {
|
|
68
|
+
display: flex;
|
|
69
|
+
flex: 1;
|
|
70
|
+
align-items: center;
|
|
71
|
+
gap: var(--nm-space-12);
|
|
72
|
+
min-width: 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.nm-select__check {
|
|
76
|
+
display: inline-flex;
|
|
77
|
+
flex-shrink: 0;
|
|
78
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { Select as SelectPrimitive } from '@base-ui/react/select';
|
|
3
|
+
import { nmClass } from '../../lib/nm-class.ts';
|
|
4
|
+
import { NmIcon } from '../nm-icon/nm-icon.tsx';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Base UI Select, in the shadcn composition, styled by NIF tokens. The choice of one value from a list that
|
|
8
|
+
* opens under the field. The list is the same surface as the dropdown menu.
|
|
9
|
+
*/
|
|
10
|
+
export function NmSelect<Value = string>(props: SelectPrimitive.Root.Props<Value>) {
|
|
11
|
+
return <SelectPrimitive.Root data-slot="select" {...props} />;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** `bare` drops its own box, for a trigger that sits inside a field. */
|
|
15
|
+
export function NmSelectTrigger({ className, children, bare, ...props }: SelectPrimitive.Trigger.Props & { bare?: boolean }) {
|
|
16
|
+
return (
|
|
17
|
+
<SelectPrimitive.Trigger data-slot="select-trigger" data-bare={bare ? '' : undefined} className={nmClass('nm-select__trigger', className as string)} {...props}>
|
|
18
|
+
{children}
|
|
19
|
+
<SelectPrimitive.Icon className="nm-select__icon">
|
|
20
|
+
<NmIcon id="chevron" />
|
|
21
|
+
</SelectPrimitive.Icon>
|
|
22
|
+
</SelectPrimitive.Trigger>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function NmSelectValue(props: SelectPrimitive.Value.Props) {
|
|
27
|
+
return <SelectPrimitive.Value data-slot="select-value" {...props} />;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** `anchor` is the element the list lines up with. It defaults to the trigger. */
|
|
31
|
+
export function NmSelectContent({ className, children, anchor, ...props }: SelectPrimitive.Popup.Props & { anchor?: HTMLElement | null }) {
|
|
32
|
+
return (
|
|
33
|
+
<SelectPrimitive.Portal>
|
|
34
|
+
<SelectPrimitive.Positioner className="nm-menu__positioner" alignItemWithTrigger={false} sideOffset={4} anchor={anchor ?? undefined}>
|
|
35
|
+
<SelectPrimitive.Popup data-slot="select-content" className={nmClass('nm-menu nm-select__popup', className as string)} {...props}>
|
|
36
|
+
<SelectPrimitive.List className="nm-select__list">{children}</SelectPrimitive.List>
|
|
37
|
+
</SelectPrimitive.Popup>
|
|
38
|
+
</SelectPrimitive.Positioner>
|
|
39
|
+
</SelectPrimitive.Portal>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function NmSelectItem({ className, children, ...props }: SelectPrimitive.Item.Props & { children: ReactNode }) {
|
|
44
|
+
return (
|
|
45
|
+
<SelectPrimitive.Item data-slot="select-item" className={nmClass('nm-menu__item nm-select__item', className as string)} {...props}>
|
|
46
|
+
<SelectPrimitive.ItemText className="nm-select__text">{children}</SelectPrimitive.ItemText>
|
|
47
|
+
<SelectPrimitive.ItemIndicator className="nm-select__check">
|
|
48
|
+
<NmIcon id="check" />
|
|
49
|
+
</SelectPrimitive.ItemIndicator>
|
|
50
|
+
</SelectPrimitive.Item>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function NmSelectGroup(props: SelectPrimitive.Group.Props) {
|
|
55
|
+
return <SelectPrimitive.Group data-slot="select-group" {...props} />;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function NmSelectLabel({ className, ...props }: SelectPrimitive.GroupLabel.Props) {
|
|
59
|
+
return <SelectPrimitive.GroupLabel data-slot="select-label" className={nmClass('nm-menu__label', className as string)} {...props} />;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function NmSelectSeparator({ className, ...props }: SelectPrimitive.Separator.Props) {
|
|
63
|
+
return <SelectPrimitive.Separator data-slot="select-separator" className={nmClass('nm-menu__separator', className as string)} {...props} />;
|
|
64
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
.nm-separator {
|
|
2
|
+
flex-shrink: 0;
|
|
3
|
+
background: var(--nm-line);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.nm-separator[data-orientation='horizontal'] {
|
|
7
|
+
width: 100%;
|
|
8
|
+
height: var(--nm-rule);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.nm-separator[data-orientation='vertical'] {
|
|
12
|
+
align-self: stretch;
|
|
13
|
+
width: var(--nm-rule);
|
|
14
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Separator as SeparatorPrimitive } from '@base-ui/react/separator';
|
|
2
|
+
import { nmClass } from '../../lib/nm-class.ts';
|
|
3
|
+
|
|
4
|
+
export function NmSeparator({ className, orientation = 'horizontal', ...props }: SeparatorPrimitive.Props) {
|
|
5
|
+
return <SeparatorPrimitive data-slot="separator" orientation={orientation} className={nmClass('nm-separator', className as string)} {...props} />;
|
|
6
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
.nm-workspace {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
display: flex;
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: var(--nm-workspace-h, 100%);
|
|
6
|
+
min-height: 0;
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
background: var(--nm-canvas);
|
|
9
|
+
color: var(--nm-fg);
|
|
10
|
+
font-family: var(--nm-font);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.nm-workspace__main {
|
|
14
|
+
display: flex;
|
|
15
|
+
flex: 1;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
min-width: 0;
|
|
18
|
+
min-height: 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.nm-workspace__body {
|
|
22
|
+
flex: 1;
|
|
23
|
+
min-height: 0;
|
|
24
|
+
padding: 0 var(--nm-space-12) var(--nm-space-12);
|
|
25
|
+
overflow: auto;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.nm-workspace__footer {
|
|
29
|
+
flex-shrink: 0;
|
|
30
|
+
padding: var(--nm-space-12);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.nm-side-panel {
|
|
34
|
+
--nm-side-panel-basis: 50%;
|
|
35
|
+
position: relative;
|
|
36
|
+
min-width: var(--nm-width-panel-min);
|
|
37
|
+
max-width: var(--nm-width-panel-max);
|
|
38
|
+
box-sizing: border-box;
|
|
39
|
+
display: flex;
|
|
40
|
+
flex: 0 0 var(--nm-side-panel-basis);
|
|
41
|
+
flex-direction: column;
|
|
42
|
+
min-height: 0;
|
|
43
|
+
border-inline-start: var(--nm-rule) solid var(--nm-divider);
|
|
44
|
+
background: var(--nm-canvas);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.nm-side-panel[hidden] {
|
|
48
|
+
display: none;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.nm-side-panel[data-size='narrow'] {
|
|
52
|
+
--nm-side-panel-basis: 33%;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.nm-side-panel[data-size='wide'] {
|
|
56
|
+
--nm-side-panel-basis: 75%;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.nm-workspace__main > .nm-toolbar,
|
|
60
|
+
.nm-side-panel > .nm-toolbar {
|
|
61
|
+
flex-shrink: 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.nm-workspace[data-height='sm'] {
|
|
65
|
+
--nm-workspace-h: var(--nm-height-workspace-sm);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.nm-workspace[data-height='lg'] {
|
|
69
|
+
--nm-workspace-h: var(--nm-height-workspace-lg);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* A panel or a table that is all of a body fills it. */
|
|
73
|
+
.nm-side-panel__body > img {
|
|
74
|
+
display: block;
|
|
75
|
+
width: 100%;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.nm-side-panel__body > .nm-panel-region {
|
|
79
|
+
height: 100%;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.nm-side-panel__body {
|
|
83
|
+
flex: 1;
|
|
84
|
+
min-height: 0;
|
|
85
|
+
padding: 0 var(--nm-space-12) var(--nm-space-12);
|
|
86
|
+
overflow: auto;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@media (max-width: 48rem) {
|
|
90
|
+
.nm-side-panel {
|
|
91
|
+
--nm-side-panel-basis: 100%;
|
|
92
|
+
}
|
|
93
|
+
}
|