@humanforest/nuxt-layer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +67 -0
- package/README.md +208 -0
- package/app.config.ts +10 -0
- package/assets/icons/forest/bike-asterisk.svg +21 -0
- package/assets/icons/forest/bike-down.svg +19 -0
- package/assets/icons/forest/bike-off.svg +20 -0
- package/assets/icons/forest/bike-up.svg +19 -0
- package/assets/icons/forest/bike-x.svg +19 -0
- package/assets/icons/forest/bike.svg +18 -0
- package/assets/icons/forest/mark-fill.svg +6 -0
- package/assets/icons/forest/mark.svg +6 -0
- package/assets/icons/forest/parking.svg +3 -0
- package/assets/icons/forest/star-fill.svg +4 -0
- package/assets/icons/forest/star.svg +4 -0
- package/assets/icons/forest/traffic-light-caution.svg +8 -0
- package/assets/icons/forest/traffic-light-go.svg +8 -0
- package/assets/icons/forest/traffic-light-lit.svg +8 -0
- package/assets/icons/forest/traffic-light-stop.svg +8 -0
- package/assets/icons/forest/traffic-light.svg +8 -0
- package/nuxt.config.ts +81 -0
- package/package.json +35 -0
- package/packages/charts/src/FBoroughShape.vue +52 -0
- package/packages/charts/src/FCalendarGrid.vue +332 -0
- package/packages/charts/src/FCellLegend.vue +54 -0
- package/packages/charts/src/FChartFrame.vue +201 -0
- package/packages/charts/src/FChartFrameSingle.vue +91 -0
- package/packages/charts/src/FChartLegend.vue +26 -0
- package/packages/charts/src/FDistributionBar.vue +224 -0
- package/packages/charts/src/FDottedMap.vue +335 -0
- package/packages/charts/src/FLondonMap.vue +399 -0
- package/packages/charts/src/FSparkline.vue +198 -0
- package/packages/charts/src/FStatusTrack.vue +151 -0
- package/packages/charts/src/cellSize.ts +46 -0
- package/packages/charts/src/distribution.ts +99 -0
- package/packages/charts/src/engine.ts +15 -0
- package/packages/charts/src/forestTooltip.ts +110 -0
- package/packages/charts/src/fromCategories.ts +43 -0
- package/packages/charts/src/index.ts +87 -0
- package/packages/charts/src/londonAreas.ts +75 -0
- package/packages/charts/src/londonGrid.ts +67 -0
- package/packages/charts/src/motionDuration.ts +49 -0
- package/packages/charts/src/presets.ts +143 -0
- package/packages/charts/src/resolveVar.ts +21 -0
- package/packages/charts/src/snapTooltip.ts +154 -0
- package/packages/charts/src/tooltipStandIn.ts +58 -0
- package/packages/charts/src/useCellScale.ts +155 -0
- package/packages/charts/src/useChartPalette.ts +61 -0
- package/packages/charts/src/useChartRepaintKey.ts +22 -0
- package/packages/charts/src/useThemeVersion.ts +17 -0
- package/packages/frames/src/FBrowserFrame.vue +53 -0
- package/packages/frames/src/FDeviceFrame.vue +242 -0
- package/packages/frames/src/FFitFrame.vue +83 -0
- package/packages/frames/src/art/iphone-11.svg +124 -0
- package/packages/frames/src/art/iphone-12.svg +601 -0
- package/packages/frames/src/art/iphone-13-pro.svg +820 -0
- package/packages/frames/src/art/iphone-13.svg +849 -0
- package/packages/frames/src/art/iphone-14.svg +681 -0
- package/packages/frames/src/art/iphone-15-pro.svg +633 -0
- package/packages/frames/src/art/iphone-15.svg +713 -0
- package/packages/frames/src/art/iphone-16-plus.svg +685 -0
- package/packages/frames/src/art/iphone-16-pro-max.svg +611 -0
- package/packages/frames/src/art/iphone-16-pro.svg +631 -0
- package/packages/frames/src/art/iphone-16.svg +713 -0
- package/packages/frames/src/art/iphone-17-pro-max.svg +355 -0
- package/packages/frames/src/art/iphone-17.svg +305 -0
- package/packages/frames/src/art/iphone-air.svg +389 -0
- package/packages/frames/src/art/iphone-se-3.svg +473 -0
- package/packages/frames/src/art/iphone-x.svg +652 -0
- package/packages/frames/src/art/pixel-10-pro-xl.svg +32 -0
- package/packages/frames/src/art/pixel-10-pro.svg +32 -0
- package/packages/frames/src/art/pixel-10.svg +32 -0
- package/packages/frames/src/art/pixel-8-pro.svg +208 -0
- package/packages/frames/src/art/pixel-8.svg +208 -0
- package/packages/frames/src/art/pixel-8a.svg +8 -0
- package/packages/frames/src/art/pixel-9-pro-xl.svg +32 -0
- package/packages/frames/src/art/pixel-9-pro.svg +34 -0
- package/packages/frames/src/art/pixel-9a.svg +25 -0
- package/packages/frames/src/art.ts +29 -0
- package/packages/frames/src/devices.ts +337 -0
- package/packages/frames/src/index.ts +15 -0
- package/packages/tokens/geo/london-boroughs.json +1 -0
- package/packages/tokens/geo/london-dots-coarse.json +1 -0
- package/packages/tokens/geo/london-dots-fine.json +1 -0
- package/packages/tokens/geo/london-dots-medium.json +1 -0
- package/packages/tokens/geo/london-dots-ultra.json +1 -0
- package/packages/tokens/geo/london-wards.json +1 -0
- package/packages/tokens/glyphs/glyphs.json +1 -0
- package/packages/tokens/logos/f-rot.svg +4 -0
- package/packages/tokens/logos/f.svg +4 -0
- package/packages/tokens/logos/favicon-c2w.svg +9 -0
- package/packages/tokens/logos/favicon-console.svg +9 -0
- package/packages/tokens/logos/favicon-ds.svg +9 -0
- package/packages/tokens/logos/favicon-fleet.svg +9 -0
- package/packages/tokens/logos/favicon-flex.svg +9 -0
- package/packages/tokens/logos/favicon-plus.svg +9 -0
- package/packages/tokens/logos/favicon-radar.svg +9 -0
- package/packages/tokens/logos/favicon-tower.svg +9 -0
- package/packages/tokens/logos/lockup-horizontal.svg +17 -0
- package/packages/tokens/logos/lockup-vertical.svg +17 -0
- package/packages/tokens/logos/mark-mono.svg +4 -0
- package/packages/tokens/logos/mark.svg +7 -0
- package/packages/tokens/logos/wordmark.svg +9 -0
- package/packages/tokens/src/colourEngine.ts +604 -0
- package/packages/tokens/src/glyphs.ts +127 -0
- package/packages/tokens/src/logo.ts +50 -0
- package/packages/tokens/src/subbrands.ts +44 -0
- package/packages/tokens/src/sublogo.ts +80 -0
- package/packages/ui/icons/forest/map/forest-place-count.svg +21 -0
- package/packages/ui/icons/forest/map/forest-place-marker.svg +17 -0
- package/packages/ui/icons/forest/map/forest-vehicle-marker.svg +73 -0
- package/packages/ui/icons/forest/map/manifest.json +373 -0
- package/packages/ui/icons/forest/map/place-count-manifest.json +83 -0
- package/packages/ui/icons/forest/map/place-manifest.json +74 -0
- package/packages/ui/src/address/address.ts +125 -0
- package/packages/ui/src/address/autofill.ts +78 -0
- package/packages/ui/src/address/geocode.ts +55 -0
- package/packages/ui/src/address/index.ts +31 -0
- package/packages/ui/src/address/validate.ts +91 -0
- package/packages/ui/src/canvas/FCanvasCard.vue +97 -0
- package/packages/ui/src/canvas/FCanvasControl.vue +121 -0
- package/packages/ui/src/canvas/FCanvasControlGroup.vue +100 -0
- package/packages/ui/src/canvas/FCanvasFlyout.vue +216 -0
- package/packages/ui/src/canvas/FCanvasHud.vue +402 -0
- package/packages/ui/src/canvas/canvasSurface.ts +39 -0
- package/packages/ui/src/canvas/index.ts +17 -0
- package/packages/ui/src/contexts/ForestContext.vue +53 -0
- package/packages/ui/src/contexts/contexts.ts +153 -0
- package/packages/ui/src/contexts/index.ts +23 -0
- package/packages/ui/src/contexts/marketing-theme.ts +214 -0
- package/packages/ui/src/contexts/mobile-theme.ts +402 -0
- package/packages/ui/src/filter/FFilterBar.vue +72 -0
- package/packages/ui/src/filter/FFilterChip.vue +362 -0
- package/packages/ui/src/filter/FFilterClauses.vue +104 -0
- package/packages/ui/src/filter/FFilterTrigger.vue +183 -0
- package/packages/ui/src/filter/filter.theme.ts +27 -0
- package/packages/ui/src/filter/filterClause.ts +265 -0
- package/packages/ui/src/filter/filterPredicate.ts +134 -0
- package/packages/ui/src/filter/filterSchema.ts +82 -0
- package/packages/ui/src/filter/index.ts +36 -0
- package/packages/ui/src/forest-preset.ts +68 -0
- package/packages/ui/src/icons.ts +79 -0
- package/packages/ui/src/index.ts +17 -0
- package/packages/ui/src/kpi/FKpi.vue +253 -0
- package/packages/ui/src/kpi/FKpiGroup.vue +161 -0
- package/packages/ui/src/kpi/index.ts +20 -0
- package/packages/ui/src/kpi/kpi.theme.ts +168 -0
- package/packages/ui/src/kpi/kpiDelta.ts +82 -0
- package/packages/ui/src/kpi/kpiFormat.ts +72 -0
- package/packages/ui/src/kpi/kpiGroupState.ts +63 -0
- package/packages/ui/src/logo/FLogo.vue +52 -0
- package/packages/ui/src/logo/FSubLogo.vue +214 -0
- package/packages/ui/src/logo/index.ts +8 -0
- package/packages/ui/src/map/FMap.vue +355 -0
- package/packages/ui/src/map/FMapCompass.vue +154 -0
- package/packages/ui/src/map/FMapCoordinates.vue +134 -0
- package/packages/ui/src/map/FMapDrawTools.vue +116 -0
- package/packages/ui/src/map/FMapFullscreen.vue +92 -0
- package/packages/ui/src/map/FMapGeolocate.vue +208 -0
- package/packages/ui/src/map/FMapLayers.vue +75 -0
- package/packages/ui/src/map/FMapLegend.vue +45 -0
- package/packages/ui/src/map/FMapPopup.vue +129 -0
- package/packages/ui/src/map/FMapRamp.vue +69 -0
- package/packages/ui/src/map/FMapRegion.vue +77 -0
- package/packages/ui/src/map/FMapScale.vue +107 -0
- package/packages/ui/src/map/FMapSearch.vue +362 -0
- package/packages/ui/src/map/FMapTilt.vue +87 -0
- package/packages/ui/src/map/FMapTools.vue +61 -0
- package/packages/ui/src/map/FMapZoom.vue +81 -0
- package/packages/ui/src/map/FMarker.vue +218 -0
- package/packages/ui/src/map/FTrackScrubber.vue +94 -0
- package/packages/ui/src/map/FVehicleLegend.vue +72 -0
- package/packages/ui/src/map/FVehicleMark.vue +166 -0
- package/packages/ui/src/map/bin.ts +196 -0
- package/packages/ui/src/map/coordinates.ts +83 -0
- package/packages/ui/src/map/density.ts +401 -0
- package/packages/ui/src/map/draw.ts +356 -0
- package/packages/ui/src/map/ease.ts +67 -0
- package/packages/ui/src/map/fullscreen.ts +59 -0
- package/packages/ui/src/map/heat.ts +160 -0
- package/packages/ui/src/map/index.ts +351 -0
- package/packages/ui/src/map/liveMarkers.ts +60 -0
- package/packages/ui/src/map/map.css +116 -0
- package/packages/ui/src/map/mapColor.ts +31 -0
- package/packages/ui/src/map/mapContext.ts +12 -0
- package/packages/ui/src/map/mapLayers.ts +55 -0
- package/packages/ui/src/map/mapLegend.ts +70 -0
- package/packages/ui/src/map/mapSearch.theme.ts +79 -0
- package/packages/ui/src/map/mapSearch.ts +279 -0
- package/packages/ui/src/map/mapUrl.ts +117 -0
- package/packages/ui/src/map/markerAsset.ts +3 -0
- package/packages/ui/src/map/padding.ts +39 -0
- package/packages/ui/src/map/place.ts +192 -0
- package/packages/ui/src/map/ramp.ts +95 -0
- package/packages/ui/src/map/regionSelect.ts +163 -0
- package/packages/ui/src/map/route.ts +167 -0
- package/packages/ui/src/map/scale.ts +329 -0
- package/packages/ui/src/map/scaleBar.ts +67 -0
- package/packages/ui/src/map/selectionModel.ts +50 -0
- package/packages/ui/src/map/sources/coordinates.ts +58 -0
- package/packages/ui/src/map/sources/mapboxPlaces.ts +71 -0
- package/packages/ui/src/map/style.ts +14 -0
- package/packages/ui/src/map/track.ts +279 -0
- package/packages/ui/src/map/useFeatureSelect.ts +230 -0
- package/packages/ui/src/map/useLiveMarkers.ts +84 -0
- package/packages/ui/src/map/useMap.ts +150 -0
- package/packages/ui/src/map/useMapDraw.ts +776 -0
- package/packages/ui/src/map/useMapOverlay.ts +421 -0
- package/packages/ui/src/map/useMapTableSelection.ts +101 -0
- package/packages/ui/src/map/useMapUrlState.ts +155 -0
- package/packages/ui/src/map/useMarkerSource.ts +163 -0
- package/packages/ui/src/map/useRegionSelect.ts +309 -0
- package/packages/ui/src/map/useTokenMode.ts +61 -0
- package/packages/ui/src/map/useTrackPlayback.ts +131 -0
- package/packages/ui/src/map/useVehicleFilter.ts +51 -0
- package/packages/ui/src/map/useVisibleFeatures.ts +124 -0
- package/packages/ui/src/map/vehicle.ts +807 -0
- package/packages/ui/src/map/vehicleFilter.ts +284 -0
- package/packages/ui/src/map/vehicleLegend.ts +155 -0
- package/packages/ui/src/map/visibleFeatures.ts +192 -0
- package/packages/ui/src/map/zone.ts +291 -0
- package/packages/ui/src/shell/FAppNavbar.vue +68 -0
- package/packages/ui/src/shell/FAppShell.vue +163 -0
- package/packages/ui/src/shell/FAppSidebar.vue +215 -0
- package/packages/ui/src/shell/FPageToolbar.vue +126 -0
- package/packages/ui/src/shell/FScrollShadow.vue +43 -0
- package/packages/ui/src/shell/FSidePanel.vue +258 -0
- package/packages/ui/src/shell/FToolbarActions.vue +32 -0
- package/packages/ui/src/shell/index.ts +33 -0
- package/packages/ui/src/shell/nav.ts +37 -0
- package/packages/ui/src/shell/pageToolbar.ts +69 -0
- package/packages/ui/src/shell/shell.ts +74 -0
- package/packages/ui/src/shell/sidePanel.ts +115 -0
- package/packages/ui/src/themes/accordion.ts +36 -0
- package/packages/ui/src/themes/alert.ts +16 -0
- package/packages/ui/src/themes/auth-form.ts +19 -0
- package/packages/ui/src/themes/avatar-group.ts +9 -0
- package/packages/ui/src/themes/avatar.ts +18 -0
- package/packages/ui/src/themes/badge.ts +51 -0
- package/packages/ui/src/themes/banner.ts +21 -0
- package/packages/ui/src/themes/breadcrumb.ts +10 -0
- package/packages/ui/src/themes/button.mechanics.ts +191 -0
- package/packages/ui/src/themes/button.ts +136 -0
- package/packages/ui/src/themes/calendar.ts +29 -0
- package/packages/ui/src/themes/card.ts +67 -0
- package/packages/ui/src/themes/carousel.ts +41 -0
- package/packages/ui/src/themes/checkbox-group.ts +20 -0
- package/packages/ui/src/themes/checkbox.ts +47 -0
- package/packages/ui/src/themes/chip.ts +50 -0
- package/packages/ui/src/themes/collapsible.ts +26 -0
- package/packages/ui/src/themes/color-picker.ts +13 -0
- package/packages/ui/src/themes/command-palette.ts +37 -0
- package/packages/ui/src/themes/container.ts +14 -0
- package/packages/ui/src/themes/context-menu.ts +38 -0
- package/packages/ui/src/themes/dashboard-group.ts +11 -0
- package/packages/ui/src/themes/dashboard-navbar.ts +10 -0
- package/packages/ui/src/themes/dashboard-panel.ts +18 -0
- package/packages/ui/src/themes/dashboard-resize-handle.ts +35 -0
- package/packages/ui/src/themes/dashboard-sidebar-collapse.ts +7 -0
- package/packages/ui/src/themes/dashboard-sidebar-toggle.ts +7 -0
- package/packages/ui/src/themes/dashboard-sidebar.ts +58 -0
- package/packages/ui/src/themes/dashboard-toolbar.ts +15 -0
- package/packages/ui/src/themes/drawer.ts +45 -0
- package/packages/ui/src/themes/dropdown-menu.ts +38 -0
- package/packages/ui/src/themes/empty.ts +43 -0
- package/packages/ui/src/themes/field-group.ts +52 -0
- package/packages/ui/src/themes/file-upload.ts +38 -0
- package/packages/ui/src/themes/footer-columns.ts +13 -0
- package/packages/ui/src/themes/footer.ts +9 -0
- package/packages/ui/src/themes/form-field.ts +25 -0
- package/packages/ui/src/themes/form.ts +22 -0
- package/packages/ui/src/themes/header.ts +12 -0
- package/packages/ui/src/themes/icon.ts +61 -0
- package/packages/ui/src/themes/index.ts +99 -0
- package/packages/ui/src/themes/input-date.ts +73 -0
- package/packages/ui/src/themes/input-menu.ts +66 -0
- package/packages/ui/src/themes/input-number.ts +58 -0
- package/packages/ui/src/themes/input-rating.ts +25 -0
- package/packages/ui/src/themes/input-tags.ts +63 -0
- package/packages/ui/src/themes/input-time.ts +70 -0
- package/packages/ui/src/themes/input.ts +148 -0
- package/packages/ui/src/themes/kbd.ts +27 -0
- package/packages/ui/src/themes/link.ts +27 -0
- package/packages/ui/src/themes/listbox.ts +48 -0
- package/packages/ui/src/themes/main.ts +6 -0
- package/packages/ui/src/themes/marquee.ts +45 -0
- package/packages/ui/src/themes/modal.ts +46 -0
- package/packages/ui/src/themes/navigation-menu.ts +80 -0
- package/packages/ui/src/themes/page-anchors.ts +7 -0
- package/packages/ui/src/themes/page-aside.ts +7 -0
- package/packages/ui/src/themes/page-card.ts +22 -0
- package/packages/ui/src/themes/page-cta.ts +18 -0
- package/packages/ui/src/themes/page-feature.ts +13 -0
- package/packages/ui/src/themes/page-header.ts +16 -0
- package/packages/ui/src/themes/page-hero.ts +15 -0
- package/packages/ui/src/themes/page-links.ts +12 -0
- package/packages/ui/src/themes/page-section.ts +14 -0
- package/packages/ui/src/themes/page.ts +7 -0
- package/packages/ui/src/themes/pagination.ts +17 -0
- package/packages/ui/src/themes/pin-input.ts +73 -0
- package/packages/ui/src/themes/popover.ts +30 -0
- package/packages/ui/src/themes/progress.ts +29 -0
- package/packages/ui/src/themes/prose.ts +45 -0
- package/packages/ui/src/themes/radio-group.ts +39 -0
- package/packages/ui/src/themes/scroll-area.ts +23 -0
- package/packages/ui/src/themes/select-menu.ts +71 -0
- package/packages/ui/src/themes/select.ts +72 -0
- package/packages/ui/src/themes/separator.ts +28 -0
- package/packages/ui/src/themes/sidebar.ts +127 -0
- package/packages/ui/src/themes/skeleton.ts +15 -0
- package/packages/ui/src/themes/slideover.ts +87 -0
- package/packages/ui/src/themes/slider.ts +48 -0
- package/packages/ui/src/themes/stepper.ts +41 -0
- package/packages/ui/src/themes/switch.ts +63 -0
- package/packages/ui/src/themes/table.ts +34 -0
- package/packages/ui/src/themes/tabs.ts +74 -0
- package/packages/ui/src/themes/textarea.ts +77 -0
- package/packages/ui/src/themes/timeline.ts +25 -0
- package/packages/ui/src/themes/toast.ts +29 -0
- package/packages/ui/src/themes/toaster.ts +66 -0
- package/packages/ui/src/themes/tooltip.ts +31 -0
- package/packages/ui/src/themes/tree.ts +41 -0
- package/packages/ui/src/themes/user.ts +28 -0
- package/styles.cdn.gen.css +2047 -0
- package/theme.gen.json +1 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Forest theme fragments — one re-export per component Forest uses, aliased to its Nuxt UI
|
|
2
|
+
// ui-config key. An EMPTY fragment ({}) records a reviewed component whose stock recipe is
|
|
3
|
+
// correct as-is — presence means reviewed, content means delta.
|
|
4
|
+
// Spread into forestPreset.ui, where this barrel is the single source of component themes
|
|
5
|
+
// (asserted by the static tests). Hand-maintained; keep the list ordered by export key.
|
|
6
|
+
|
|
7
|
+
export { accordionTheme as accordion } from './accordion';
|
|
8
|
+
export { alertTheme as alert } from './alert';
|
|
9
|
+
export { authFormTheme as authForm } from './auth-form';
|
|
10
|
+
export { avatarTheme as avatar } from './avatar';
|
|
11
|
+
export { avatarGroupTheme as avatarGroup } from './avatar-group';
|
|
12
|
+
export { badgeTheme as badge } from './badge';
|
|
13
|
+
export { bannerTheme as banner } from './banner';
|
|
14
|
+
export { breadcrumbTheme as breadcrumb } from './breadcrumb';
|
|
15
|
+
// button.mechanics is deliberately absent — it exports the button's private recipe/palette
|
|
16
|
+
// constants, not a component theme.
|
|
17
|
+
export { buttonTheme as button } from './button';
|
|
18
|
+
export { calendarTheme as calendar } from './calendar';
|
|
19
|
+
export { cardTheme as card } from './card';
|
|
20
|
+
export { carouselTheme as carousel } from './carousel';
|
|
21
|
+
export { checkboxTheme as checkbox } from './checkbox';
|
|
22
|
+
export { checkboxGroupTheme as checkboxGroup } from './checkbox-group';
|
|
23
|
+
export { chipTheme as chip } from './chip';
|
|
24
|
+
export { collapsibleTheme as collapsible } from './collapsible';
|
|
25
|
+
export { colorPickerTheme as colorPicker } from './color-picker';
|
|
26
|
+
export { commandPaletteTheme as commandPalette } from './command-palette';
|
|
27
|
+
export { containerTheme as container } from './container';
|
|
28
|
+
export { contextMenuTheme as contextMenu } from './context-menu';
|
|
29
|
+
export { dashboardGroupTheme as dashboardGroup } from './dashboard-group';
|
|
30
|
+
export { dashboardNavbarTheme as dashboardNavbar } from './dashboard-navbar';
|
|
31
|
+
export { dashboardPanelTheme as dashboardPanel } from './dashboard-panel';
|
|
32
|
+
export { dashboardResizeHandleTheme as dashboardResizeHandle } from './dashboard-resize-handle';
|
|
33
|
+
export { dashboardSidebarTheme as dashboardSidebar } from './dashboard-sidebar';
|
|
34
|
+
export { dashboardSidebarCollapseTheme as dashboardSidebarCollapse } from './dashboard-sidebar-collapse';
|
|
35
|
+
export { dashboardSidebarToggleTheme as dashboardSidebarToggle } from './dashboard-sidebar-toggle';
|
|
36
|
+
export { dashboardToolbarTheme as dashboardToolbar } from './dashboard-toolbar';
|
|
37
|
+
export { drawerTheme as drawer } from './drawer';
|
|
38
|
+
export { dropdownMenuTheme as dropdownMenu } from './dropdown-menu';
|
|
39
|
+
export { emptyTheme as empty } from './empty';
|
|
40
|
+
export { footerTheme as footer } from './footer';
|
|
41
|
+
export { footerColumnsTheme as footerColumns } from './footer-columns';
|
|
42
|
+
export { fieldGroupTheme as fieldGroup } from './field-group';
|
|
43
|
+
export { fileUploadTheme as fileUpload } from './file-upload';
|
|
44
|
+
export { formTheme as form } from './form';
|
|
45
|
+
export { formFieldTheme as formField } from './form-field';
|
|
46
|
+
export { headerTheme as header } from './header';
|
|
47
|
+
export { iconTheme as icon } from './icon';
|
|
48
|
+
export { inputDateTheme as inputDate } from './input-date';
|
|
49
|
+
export { inputMenuTheme as inputMenu } from './input-menu';
|
|
50
|
+
export { inputNumberTheme as inputNumber } from './input-number';
|
|
51
|
+
export { inputRatingTheme as inputRating } from './input-rating';
|
|
52
|
+
export { inputTagsTheme as inputTags } from './input-tags';
|
|
53
|
+
export { inputTimeTheme as inputTime } from './input-time';
|
|
54
|
+
export { inputTheme as input } from './input';
|
|
55
|
+
export { kbdTheme as kbd } from './kbd';
|
|
56
|
+
export { linkTheme as link } from './link';
|
|
57
|
+
export { listboxTheme as listbox } from './listbox';
|
|
58
|
+
export { mainTheme as main } from './main';
|
|
59
|
+
export { marqueeTheme as marquee } from './marquee';
|
|
60
|
+
export { modalTheme as modal } from './modal';
|
|
61
|
+
export { navigationMenuTheme as navigationMenu } from './navigation-menu';
|
|
62
|
+
export { pageTheme as page } from './page';
|
|
63
|
+
export { pageAnchorsTheme as pageAnchors } from './page-anchors';
|
|
64
|
+
export { pageAsideTheme as pageAside } from './page-aside';
|
|
65
|
+
export { pageCardTheme as pageCard } from './page-card';
|
|
66
|
+
export { pageCtaTheme as pageCta } from './page-cta';
|
|
67
|
+
export { pageFeatureTheme as pageFeature } from './page-feature';
|
|
68
|
+
export { pageHeaderTheme as pageHeader } from './page-header';
|
|
69
|
+
export { pageHeroTheme as pageHero } from './page-hero';
|
|
70
|
+
export { pageLinksTheme as pageLinks } from './page-links';
|
|
71
|
+
export { pageSectionTheme as pageSection } from './page-section';
|
|
72
|
+
export { paginationTheme as pagination } from './pagination';
|
|
73
|
+
export { pinInputTheme as pinInput } from './pin-input';
|
|
74
|
+
export { popoverTheme as popover } from './popover';
|
|
75
|
+
export { progressTheme as progress } from './progress';
|
|
76
|
+
// Prose components are namespaced under ui.prose.* — the fragment runs stock, carrying only the
|
|
77
|
+
// `ed-demo` marker the docs editorial grid reads off a demo pane.
|
|
78
|
+
export { proseTheme as prose } from './prose';
|
|
79
|
+
export { radioGroupTheme as radioGroup } from './radio-group';
|
|
80
|
+
export { scrollAreaTheme as scrollArea } from './scroll-area';
|
|
81
|
+
export { selectMenuTheme as selectMenu } from './select-menu';
|
|
82
|
+
export { selectTheme as select } from './select';
|
|
83
|
+
export { separatorTheme as separator } from './separator';
|
|
84
|
+
export { sidebarTheme as sidebar } from './sidebar';
|
|
85
|
+
export { skeletonTheme as skeleton } from './skeleton';
|
|
86
|
+
export { slideoverTheme as slideover } from './slideover';
|
|
87
|
+
export { sliderTheme as slider } from './slider';
|
|
88
|
+
export { stepperTheme as stepper } from './stepper';
|
|
89
|
+
export { switchTheme as switch } from './switch';
|
|
90
|
+
export { tableTheme as table } from './table';
|
|
91
|
+
export { tabsTheme as tabs } from './tabs';
|
|
92
|
+
export { textareaTheme as textarea } from './textarea';
|
|
93
|
+
export { timelineTheme as timeline } from './timeline';
|
|
94
|
+
export { toastTheme as toast } from './toast';
|
|
95
|
+
// toaster is the STACK (viewport, entry/exit, swipe); toast above is a single notification's surface.
|
|
96
|
+
export { toasterTheme as toaster } from './toaster';
|
|
97
|
+
export { tooltipTheme as tooltip } from './tooltip';
|
|
98
|
+
export { treeTheme as tree } from './tree';
|
|
99
|
+
export { userTheme as user } from './user';
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forest theme fragment — UInputDate (date / range picker field).
|
|
3
|
+
*
|
|
4
|
+
* Forest opinions applied:
|
|
5
|
+
* - `base`: the recessed depth line ported from UInput (inset top edge at rest, dropped on focus)
|
|
6
|
+
* so the field family shares one pressed-into-the-page identity. Radius stays stock rounded-md.
|
|
7
|
+
* - `segment`: focused segments receive `focus:rounded` (a mild inner radius) so the highlight
|
|
8
|
+
* bubble fits the overall radius language rather than appearing perfectly square.
|
|
9
|
+
* - `leadingIcon` / `trailingIcon`: already inherit `text-dimmed` from stock; no override needed.
|
|
10
|
+
* - `separatorIcon`: sized and dimmed to match the rest of the field chrome at every size.
|
|
11
|
+
*
|
|
12
|
+
* - touch ladder: like UInput, each size swaps to its touch rung (min-h 28/36/40/44/52)
|
|
13
|
+
* (py, gap, segment/base type, icon) so the field reads as a bigger version of itself. Horizontal
|
|
14
|
+
* px is held (stock's absolute leading / trailing ps- / pe- insets would be clobbered). Like UInput
|
|
15
|
+
* the base type carries a responsive `md:text-*` shrink, so the coarse type bump targets the next
|
|
16
|
+
* size's EFFECTIVE desktop value (sm→md `touch:text-sm`, lg→xl `touch:text-base`) rather than its
|
|
17
|
+
* base token, or a bumped sm would outgrow md and invert the ladder. xl has a touch rung of
|
|
18
|
+
* its own (52), and the mobile cut needs no escape — it lands on the same rung a coarse pointer would.
|
|
19
|
+
*
|
|
20
|
+
* Slots touched: segment; size variant (touch deltas).
|
|
21
|
+
* Slot names sourced from: apps/docs/node_modules/.nuxt-ui/ui/input-date.ts
|
|
22
|
+
*
|
|
23
|
+
* Focus rings (outline/subtle variants × every colour) resolve correctly via Nuxt UI's own
|
|
24
|
+
* compoundVariants reading --ui-color-<family>-* — already wired to the Forest OKLCH ramps in
|
|
25
|
+
* docs.css. No override needed here.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
export const inputDateTheme = {
|
|
29
|
+
slots: {
|
|
30
|
+
// The recessed depth line, ported from UInput so the field family shares one "pressed-into-the-
|
|
31
|
+
// page" identity: a solid inset top edge (no blur) at rest, dropped on focus (has-focus-visible,
|
|
32
|
+
// since focus lives on a segment) so the active field lifts to its focus ring — the same
|
|
33
|
+
// rest-pressed / focus-lifted behaviour UInput now uses. Depth scales per size via the var below;
|
|
34
|
+
// the recess colour is mode-aware (forest.css). transition-[color,box-shadow] eases it in/out.
|
|
35
|
+
base: 'transition-[color,box-shadow] duration-(--motion-fast) shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)] has-focus-visible:shadow-none',
|
|
36
|
+
// focus:rounded — mild inner radius on the active segment bubble matches the field's soft radius.
|
|
37
|
+
segment: 'focus:rounded',
|
|
38
|
+
},
|
|
39
|
+
// Per-size recessed depth (2/2/3/3/4, shallower on short fields) + the touch ladder — one
|
|
40
|
+
// size up as a unit. Each size lists only its deltas.
|
|
41
|
+
// `touch:` = the shared TOUCH ladder (styles/forest.css) — height+type twin of button.ts/input.ts
|
|
42
|
+
// so a joined <UFieldGroup> matches. Fired by a coarse pointer or by the mobile cut's
|
|
43
|
+
// baked marker — same numbers either way, so a real phone can't step twice.
|
|
44
|
+
variants: {
|
|
45
|
+
size: {
|
|
46
|
+
xs: { base: '[--forest-input-depth:2px] touch:min-h-7 touch:gap-1.5' }, // touch 28
|
|
47
|
+
sm: { base: '[--forest-input-depth:2px] touch:min-h-9 touch:text-sm touch:rounded-md touch:[--forest-input-depth:3px]', leadingIcon: 'touch:size-5', trailingIcon: 'touch:size-5' }, // touch 36 (type = md's effective value; stock md:text-sm shrink)
|
|
48
|
+
md: { base: '[--forest-input-depth:3px] touch:min-h-10 touch:text-sm touch:gap-2' }, // touch 40
|
|
49
|
+
lg: { base: '[--forest-input-depth:3px] touch:min-h-11 touch:text-base touch:rounded-lg touch:[--forest-input-depth:4px]', leadingIcon: 'touch:size-6', trailingIcon: 'touch:size-6' }, // touch 44
|
|
50
|
+
xl: { base: '[--forest-input-depth:4px] touch:min-h-13 touch:text-lg touch:rounded-lg touch:[--forest-input-depth:4px]', leadingIcon: 'touch:size-7', trailingIcon: 'touch:size-7' }, // touch 52
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
compoundVariants: [
|
|
54
|
+
// ghost / none carry no fill, so a resting depth line floats with nothing to recess into. ghost
|
|
55
|
+
// picks it up on hover (the elevated fill arrives); none stays flat.
|
|
56
|
+
{ variant: 'ghost', class: { base: 'shadow-none hover:shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)]' } },
|
|
57
|
+
{ variant: 'none', class: { base: 'shadow-none' } },
|
|
58
|
+
// Recess tint gated to `highlight` (the persistent coloured-ring state) — a plain rest field is
|
|
59
|
+
// neutral (ring-accented border), so the line only takes the accent where the border does.
|
|
60
|
+
// neutral omitted (its highlight ring is the inverted tone, matched by the neutral line).
|
|
61
|
+
{ color: 'primary', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-primary)]' } },
|
|
62
|
+
{ color: 'secondary', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-secondary)]' } },
|
|
63
|
+
{ color: 'success', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-success)]' } },
|
|
64
|
+
{ color: 'info', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-info)]' } },
|
|
65
|
+
{ color: 'warning', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-warning)]' } },
|
|
66
|
+
{ color: 'error', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-error)]' } },
|
|
67
|
+
{ color: 'forest', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-forest)]' } },
|
|
68
|
+
{ color: 'maple', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-maple)]' } },
|
|
69
|
+
{ color: 'river', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-river)]' } },
|
|
70
|
+
{ color: 'warm', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-warm)]' } },
|
|
71
|
+
{ color: 'acid', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-acid)]' } },
|
|
72
|
+
],
|
|
73
|
+
} as const;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forest theme fragment — UInputMenu (autocomplete combobox: input + dropdown panel).
|
|
3
|
+
*
|
|
4
|
+
* Forest opinions applied:
|
|
5
|
+
* - base (input): the recessed depth line ported from UInput (inset top edge at rest, dropped on
|
|
6
|
+
* focus) so the field family shares one pressed-into-the-page identity; focus:outline-none
|
|
7
|
+
* suppresses the native ring; the brand forest-500 focus ring on outline.
|
|
8
|
+
* - touch ladder: each size takes its touch rung (min-h 28/36/40/44/52) under a coarse
|
|
9
|
+
* pointer or the mobile cut — box, gap,
|
|
10
|
+
* effective text, icons); px held. The base carries a responsive `md:text-*` shrink, so the coarse
|
|
11
|
+
* type bump targets the next size's EFFECTIVE value (sm→md `touch:text-sm`, lg→xl `touch:text-base`).
|
|
12
|
+
* - recess tint: an explicit intent tints the depth line to its ring colour, but only in `highlight`.
|
|
13
|
+
* - content: opens/closes on the Forest motion tokens.
|
|
14
|
+
* - item: before:rounded-sm (8px) — concentric inside the 12px panel.
|
|
15
|
+
* - tagsItem: rounded-md — comfortable tag pills, consistent with the Forest field family.
|
|
16
|
+
*
|
|
17
|
+
* Slots touched: base, content, item, tagsItem; size variant (depth + touch); variant (focus ring).
|
|
18
|
+
* Slot names sourced from: apps/docs/node_modules/.nuxt-ui/ui/input-menu.ts
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export const inputMenuTheme = {
|
|
22
|
+
slots: {
|
|
23
|
+
base: 'transition-[color,box-shadow] duration-(--motion-fast) shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)] focus-visible:shadow-none focus:outline-none',
|
|
24
|
+
// Panel radius/ring come from stock (rounded-md / ring-default); opens/closes with Forest motion.
|
|
25
|
+
content: 'data-[state=open]:animate-[scale-in_var(--motion-base)_var(--motion-ease-out)] data-[state=closed]:animate-[scale-out_var(--motion-fast)_var(--motion-ease-out)]',
|
|
26
|
+
// Item slab: before:rounded-sm (8px) — concentric inside the 12px panel.
|
|
27
|
+
item: 'before:rounded-sm',
|
|
28
|
+
// Tag pills in multiple mode: rounded-md — comfortable, consistent with the Forest field family.
|
|
29
|
+
tagsItem: 'rounded-md',
|
|
30
|
+
},
|
|
31
|
+
variants: {
|
|
32
|
+
variant: {
|
|
33
|
+
// Reinforce the focus ring with forest-500 so the open combobox matches UInput's ring colour.
|
|
34
|
+
outline: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--forest-500)]',
|
|
35
|
+
subtle: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--forest-500)]',
|
|
36
|
+
},
|
|
37
|
+
// Per-size recessed depth (2/2/3/3/4) + the touch ladder. Object-shaped; deltas only.
|
|
38
|
+
// `touch:` = the shared TOUCH ladder (styles/forest.css) — height+type twin of button.ts/input.ts
|
|
39
|
+
// so a joined <UFieldGroup> matches. Fired by a coarse pointer or by the mobile cut's
|
|
40
|
+
// baked marker — same numbers either way, so a real phone can't step twice.
|
|
41
|
+
size: {
|
|
42
|
+
xs: { base: '[--forest-input-depth:2px] touch:min-h-7 touch:gap-1.5' }, // touch 28
|
|
43
|
+
sm: { base: '[--forest-input-depth:2px] touch:min-h-9 touch:text-sm touch:rounded-md touch:[--forest-input-depth:3px]', leadingIcon: 'touch:size-5', trailingIcon: 'touch:size-5' }, // touch 36
|
|
44
|
+
md: { base: '[--forest-input-depth:3px] touch:min-h-10 touch:text-sm touch:gap-2' }, // touch 40
|
|
45
|
+
lg: { base: '[--forest-input-depth:3px] touch:min-h-11 touch:text-base touch:rounded-lg touch:[--forest-input-depth:4px]', leadingIcon: 'touch:size-6', trailingIcon: 'touch:size-6' }, // touch 44
|
|
46
|
+
xl: { base: '[--forest-input-depth:4px] touch:min-h-13 touch:text-lg touch:rounded-lg touch:[--forest-input-depth:4px]', leadingIcon: 'touch:size-7', trailingIcon: 'touch:size-7' }, // touch 52
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
compoundVariants: [
|
|
50
|
+
// ghost / none carry no fill, so a resting depth line floats with nothing to recess into.
|
|
51
|
+
{ variant: 'ghost', class: { base: 'shadow-none hover:shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)]' } },
|
|
52
|
+
{ variant: 'none', class: { base: 'shadow-none' } },
|
|
53
|
+
// Recess tint gated to `highlight`; a plain rest field keeps the neutral line. neutral omitted.
|
|
54
|
+
{ color: 'primary', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-primary)]' } },
|
|
55
|
+
{ color: 'secondary', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-secondary)]' } },
|
|
56
|
+
{ color: 'success', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-success)]' } },
|
|
57
|
+
{ color: 'info', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-info)]' } },
|
|
58
|
+
{ color: 'warning', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-warning)]' } },
|
|
59
|
+
{ color: 'error', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-error)]' } },
|
|
60
|
+
{ color: 'forest', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-forest)]' } },
|
|
61
|
+
{ color: 'maple', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-maple)]' } },
|
|
62
|
+
{ color: 'river', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-river)]' } },
|
|
63
|
+
{ color: 'warm', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-warm)]' } },
|
|
64
|
+
{ color: 'acid', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-acid)]' } },
|
|
65
|
+
],
|
|
66
|
+
} as const;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forest theme fragment — UInputNumber (stepper number field).
|
|
3
|
+
*
|
|
4
|
+
* Forest opinions applied:
|
|
5
|
+
* - `base`: the recessed depth line ported from UInput (inset top edge at rest, dropped on focus)
|
|
6
|
+
* so the field family shares one pressed-into-the-page identity; focus:outline-none suppresses the
|
|
7
|
+
* stock ring. Radius/shape stay stock.
|
|
8
|
+
* - touch ladder: like UInput, each size swaps to its touch rung (min-h 28/36/40/44/52)
|
|
9
|
+
* (py, gap, effective text). Horizontal px is held (the absolute increment/decrement insets would
|
|
10
|
+
* be clobbered). The base type carries a responsive `md:text-*` shrink, so the coarse type bump
|
|
11
|
+
* targets the next size's EFFECTIVE value (sm→md `touch:text-sm`, lg→xl `touch:text-base`) or a
|
|
12
|
+
* promoted sm would outgrow md and invert the ladder. xl has a touch rung of its own (52).
|
|
13
|
+
* - recess tint: an explicit intent tints the depth line to its ring colour, but only in `highlight`
|
|
14
|
+
* (the persistent coloured-ring state) — a plain rest field stays neutral. Same rule as UInput.
|
|
15
|
+
*
|
|
16
|
+
* The size variant is a FLAT string per size (stock's own shape — it targets the base slot); the
|
|
17
|
+
* touch deltas + depth var append as flat strings to match, or the merge would drop them.
|
|
18
|
+
*
|
|
19
|
+
* Slot names sourced from: apps/docs/node_modules/.nuxt-ui/ui/input-number.ts
|
|
20
|
+
* Focus rings (outline/subtle × every colour) resolve via Nuxt UI's own compoundVariants reading
|
|
21
|
+
* --ui-color-<family>-*, wired to the Forest ramps in docs.css. No override needed there.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
export const inputNumberTheme = {
|
|
25
|
+
slots: {
|
|
26
|
+
base: 'transition-[color,box-shadow] duration-(--motion-fast) shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)] focus-visible:shadow-none focus:outline-none',
|
|
27
|
+
},
|
|
28
|
+
variants: {
|
|
29
|
+
// Per-size recessed depth (2/2/3/3/4) + the touch ladder. FLAT strings — matches stock's size
|
|
30
|
+
// shape (a { base: … } object here would be dropped by the merge).
|
|
31
|
+
size: {
|
|
32
|
+
xs: '[--forest-input-depth:2px] touch:min-h-7 touch:gap-1.5', // touch 28
|
|
33
|
+
sm: '[--forest-input-depth:2px] touch:min-h-9 touch:text-sm touch:rounded-md touch:[--forest-input-depth:3px]', // touch 36 (type = md's effective value; stock md:text-sm shrink)
|
|
34
|
+
md: '[--forest-input-depth:3px] touch:min-h-10 touch:text-sm touch:gap-2', // touch 40
|
|
35
|
+
lg: '[--forest-input-depth:3px] touch:min-h-11 touch:text-base touch:rounded-lg touch:[--forest-input-depth:4px]', // touch 44
|
|
36
|
+
xl: '[--forest-input-depth:4px] touch:min-h-13 touch:text-lg touch:rounded-lg touch:[--forest-input-depth:4px]', // touch 52
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
compoundVariants: [
|
|
40
|
+
// ghost / none carry no fill, so a resting depth line floats with nothing to recess into. ghost
|
|
41
|
+
// picks it up on hover (elevated fill arrives); none stays flat.
|
|
42
|
+
{ variant: 'ghost', class: { base: 'shadow-none hover:shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)]' } },
|
|
43
|
+
{ variant: 'none', class: { base: 'shadow-none' } },
|
|
44
|
+
// Recess tint gated to `highlight` (the persistent coloured-ring state); a plain rest field keeps
|
|
45
|
+
// the neutral line. neutral omitted (its highlight ring is the inverted tone).
|
|
46
|
+
{ color: 'primary', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-primary)]' } },
|
|
47
|
+
{ color: 'secondary', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-secondary)]' } },
|
|
48
|
+
{ color: 'success', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-success)]' } },
|
|
49
|
+
{ color: 'info', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-info)]' } },
|
|
50
|
+
{ color: 'warning', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-warning)]' } },
|
|
51
|
+
{ color: 'error', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-error)]' } },
|
|
52
|
+
{ color: 'forest', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-forest)]' } },
|
|
53
|
+
{ color: 'maple', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-maple)]' } },
|
|
54
|
+
{ color: 'river', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-river)]' } },
|
|
55
|
+
{ color: 'warm', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-warm)]' } },
|
|
56
|
+
{ color: 'acid', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-acid)]' } },
|
|
57
|
+
],
|
|
58
|
+
} as const;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forest theme fragment for UInputRating.
|
|
3
|
+
*
|
|
4
|
+
* Amber by default — the universal gold-star rating look. `color` is a variant, so a
|
|
5
|
+
* defaultVariants override is the clean lever (stock defaults to primary). Explicit color on a
|
|
6
|
+
* component still wins. The filled star glyph is the vendored solid star (the preset's icons.star
|
|
7
|
+
* alias); the empty state reuses it muted unless a component passes its own empty-icon.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export const inputRatingTheme = {
|
|
11
|
+
defaultVariants: { color: 'warning' },
|
|
12
|
+
|
|
13
|
+
// Touch: each star promotes ONE size up under a coarse pointer — the whole ladder is a square
|
|
14
|
+
// dimension (size-3 → size-7), so promotion is a straight one-step size bump on both the hit area
|
|
15
|
+
// (`item`) and the glyph (`icon`). xl (size-7) is the ceiling; deltas only. `coarse:` carries the
|
|
16
|
+
// :not(.cut-fixed) escape so a baked mobile cut opts out.
|
|
17
|
+
variants: {
|
|
18
|
+
size: {
|
|
19
|
+
xs: { item: 'coarse:size-4', icon: 'coarse:size-4' },
|
|
20
|
+
sm: { item: 'coarse:size-5', icon: 'coarse:size-5' },
|
|
21
|
+
md: { item: 'coarse:size-6', icon: 'coarse:size-6' },
|
|
22
|
+
lg: { item: 'coarse:size-7', icon: 'coarse:size-7' },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
} as const
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forest theme fragment — UInputTags (tag/token input: a field of removable chips + a text input).
|
|
3
|
+
*
|
|
4
|
+
* Forest opinions applied:
|
|
5
|
+
* - base (field): the recessed depth line ported from UInput (inset top edge at rest, dropped on
|
|
6
|
+
* focus) so the field family shares one pressed-into-the-page identity. Focus lives on the inner
|
|
7
|
+
* input, so the drop and the stock ring both key off `has-focus-visible`. The ring already follows
|
|
8
|
+
* the colour intent (ring-primary → forest via the alias), so no forest-500 override is needed.
|
|
9
|
+
* - touch ladder: each size takes its touch rung (min-h 28/36/40/44/52) under a coarse
|
|
10
|
+
* pointer or the mobile cut — box, gap,
|
|
11
|
+
* effective text, icons); px held. The base carries a responsive `md:text-*` shrink, so the coarse
|
|
12
|
+
* type bump targets the next size's EFFECTIVE value (sm→md `touch:text-sm`, lg→xl `touch:text-base`).
|
|
13
|
+
* - recess tint: an explicit intent tints the depth line to its ring colour, but only in `highlight`.
|
|
14
|
+
* - item (chip): rounded-lg (Forest soft radius, not stock's rounded-sm).
|
|
15
|
+
* - itemDelete (remove button): rounded-sm — a tight close icon inside a pill should not itself be
|
|
16
|
+
* pill-shaped (avoids a nested pill-in-pill look).
|
|
17
|
+
*
|
|
18
|
+
* Slots touched: base, item, itemDelete; size variant (depth + touch).
|
|
19
|
+
* Slot names sourced from: apps/docs/node_modules/.nuxt-ui/ui/input-tags.ts
|
|
20
|
+
* The remove-icon (appConfig close) and the raw inner input slot are stock.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
export const inputTagsTheme = {
|
|
24
|
+
slots: {
|
|
25
|
+
base: 'transition-[color,box-shadow] duration-(--motion-fast) shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)] has-focus-visible:shadow-none',
|
|
26
|
+
// Pill chip: rounded-lg (Forest soft radius, not stock's rounded-sm).
|
|
27
|
+
item: 'rounded-lg',
|
|
28
|
+
// rounded-sm (not rounded-lg) — a tight close icon inside a pill should not itself be pill-shaped.
|
|
29
|
+
itemDelete: 'rounded-sm',
|
|
30
|
+
},
|
|
31
|
+
variants: {
|
|
32
|
+
// Per-size recessed depth (2/2/3/3/4) + the touch ladder. Object-shaped; deltas only.
|
|
33
|
+
// `touch:` = the shared TOUCH ladder (styles/forest.css) — height+type twin of button.ts/input.ts
|
|
34
|
+
// so a joined <UFieldGroup> matches. Fired by a coarse pointer or by the mobile cut's
|
|
35
|
+
// baked marker — same numbers either way, so a real phone can't step twice.
|
|
36
|
+
size: {
|
|
37
|
+
xs: { base: '[--forest-input-depth:2px] touch:min-h-7 touch:gap-1.5' }, // touch 28
|
|
38
|
+
sm: { base: '[--forest-input-depth:2px] touch:min-h-9 touch:text-sm touch:rounded-md touch:[--forest-input-depth:3px]', leadingIcon: 'touch:size-5', trailingIcon: 'touch:size-5' }, // touch 36
|
|
39
|
+
md: { base: '[--forest-input-depth:3px] touch:min-h-10 touch:text-sm touch:gap-2' }, // touch 40
|
|
40
|
+
lg: { base: '[--forest-input-depth:3px] touch:min-h-11 touch:text-base touch:rounded-lg touch:[--forest-input-depth:4px]', leadingIcon: 'touch:size-6', trailingIcon: 'touch:size-6' }, // touch 44
|
|
41
|
+
xl: { base: '[--forest-input-depth:4px] touch:min-h-13 touch:text-lg touch:rounded-lg touch:[--forest-input-depth:4px]', leadingIcon: 'touch:size-7', trailingIcon: 'touch:size-7' }, // touch 52
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
compoundVariants: [
|
|
45
|
+
// ghost / none carry no fill, so a resting depth line floats with nothing to recess into. ghost
|
|
46
|
+
// picks it up on hover (elevated fill arrives); none stays flat.
|
|
47
|
+
{ variant: 'ghost', class: { base: 'shadow-none hover:shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)]' } },
|
|
48
|
+
{ variant: 'none', class: { base: 'shadow-none' } },
|
|
49
|
+
// Recess tint gated to `highlight` (the persistent coloured-ring state); a plain rest field keeps
|
|
50
|
+
// the neutral line. neutral omitted (its highlight ring is the inverted tone).
|
|
51
|
+
{ color: 'primary', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-primary)]' } },
|
|
52
|
+
{ color: 'secondary', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-secondary)]' } },
|
|
53
|
+
{ color: 'success', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-success)]' } },
|
|
54
|
+
{ color: 'info', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-info)]' } },
|
|
55
|
+
{ color: 'warning', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-warning)]' } },
|
|
56
|
+
{ color: 'error', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-error)]' } },
|
|
57
|
+
{ color: 'forest', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-forest)]' } },
|
|
58
|
+
{ color: 'maple', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-maple)]' } },
|
|
59
|
+
{ color: 'river', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-river)]' } },
|
|
60
|
+
{ color: 'warm', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-warm)]' } },
|
|
61
|
+
{ color: 'acid', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-acid)]' } },
|
|
62
|
+
],
|
|
63
|
+
} as const;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forest theme fragment — UInputTime (time-picker field).
|
|
3
|
+
*
|
|
4
|
+
* Forest opinions applied:
|
|
5
|
+
*
|
|
6
|
+
* outline variant:
|
|
7
|
+
* Brand forest-500 focus ring on the wrapper — ring-[var(--forest-500)] — consistent with
|
|
8
|
+
* UInput, USelect, and UTextarea. Keeps the full set of field controls on one focus-ring
|
|
9
|
+
* language.
|
|
10
|
+
*
|
|
11
|
+
* subtle variant:
|
|
12
|
+
* Same brand forest-500 focus ring as outline, matching USelect's subtle treatment.
|
|
13
|
+
*
|
|
14
|
+
* base/segment carry no resting Forest opinion — shape and state styling match stock; the size
|
|
15
|
+
* variant adds the touch ladder, so the field takes its touch rung on a finger pointer.
|
|
16
|
+
* Slot names sourced from: apps/docs/node_modules/.nuxt-ui/ui/input-time.ts
|
|
17
|
+
*
|
|
18
|
+
* Focus rings on compound colour variants (outline × primary/error/…) are handled by Nuxt UI's
|
|
19
|
+
* own compoundVariants using the semantic colour vars, which are wired to the Forest OKLCH ramps
|
|
20
|
+
* in docs.css. No override needed — they resolve to the correct ramp values automatically.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
export const inputTimeTheme = {
|
|
24
|
+
slots: {
|
|
25
|
+
// Recessed depth line ported from UInput — inset top edge at rest, dropped on focus (has-focus-
|
|
26
|
+
// visible; focus lives on a segment) so the field lifts to its ring. Depth scales per size below;
|
|
27
|
+
// recess colour is mode-aware + tints to the intent (colour variant). Same identity as every field.
|
|
28
|
+
base: 'transition-[color,box-shadow] duration-(--motion-fast) shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)] has-focus-visible:shadow-none',
|
|
29
|
+
},
|
|
30
|
+
variants: {
|
|
31
|
+
variant: {
|
|
32
|
+
// Brand forest-500 focus ring — consistent with UInput / USelect / UTextarea.
|
|
33
|
+
outline: 'hover:bg-elevated disabled:bg-default focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--forest-500)]',
|
|
34
|
+
// Subtle gets the same brand focus-ring treatment.
|
|
35
|
+
subtle: 'hover:bg-accented/75 disabled:bg-elevated focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[var(--forest-500)]',
|
|
36
|
+
},
|
|
37
|
+
// Coarse touch step-up — one size up as a unit (py, gap, segment/base type, icon); px held. Same
|
|
38
|
+
// ladder as UInputDate — the two share a size scale. Every rung has a touch twin, xl
|
|
39
|
+
// included (52), so the mobile cut needs no escape: it lands on the same rung.
|
|
40
|
+
// `touch:` = the shared TOUCH ladder (styles/forest.css) — height+type twin of button.ts/input.ts
|
|
41
|
+
// so a joined <UFieldGroup> matches. Fired by a coarse pointer or by the mobile cut's
|
|
42
|
+
// baked marker — same numbers either way, so a real phone can't step twice.
|
|
43
|
+
size: {
|
|
44
|
+
xs: { base: '[--forest-input-depth:2px] touch:min-h-7 touch:gap-1.5' }, // touch 28
|
|
45
|
+
sm: { base: '[--forest-input-depth:2px] touch:min-h-9 touch:text-sm touch:rounded-md touch:[--forest-input-depth:3px]', leadingIcon: 'touch:size-5', trailingIcon: 'touch:size-5' }, // touch 36 (type = md's effective value; stock md:text-sm shrink)
|
|
46
|
+
md: { base: '[--forest-input-depth:3px] touch:min-h-10 touch:text-sm touch:gap-2' }, // touch 40
|
|
47
|
+
lg: { base: '[--forest-input-depth:3px] touch:min-h-11 touch:text-base touch:rounded-lg touch:[--forest-input-depth:4px]', leadingIcon: 'touch:size-6', trailingIcon: 'touch:size-6' }, // touch 44
|
|
48
|
+
xl: { base: '[--forest-input-depth:4px] touch:min-h-13 touch:text-lg touch:rounded-lg touch:[--forest-input-depth:4px]', leadingIcon: 'touch:size-7', trailingIcon: 'touch:size-7' }, // touch 52
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
compoundVariants: [
|
|
52
|
+
// ghost / none carry no fill, so a resting depth line floats with nothing to recess into. ghost
|
|
53
|
+
// picks it up on hover (elevated fill arrives); none stays flat.
|
|
54
|
+
{ variant: 'ghost', class: { base: 'shadow-none hover:shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)]' } },
|
|
55
|
+
{ variant: 'none', class: { base: 'shadow-none' } },
|
|
56
|
+
// Recess tint gated to `highlight` (persistent coloured ring) — a plain rest field is neutral, so
|
|
57
|
+
// the line only takes the accent where the border does. neutral omitted (inverted highlight ring).
|
|
58
|
+
{ color: 'primary', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-primary)]' } },
|
|
59
|
+
{ color: 'secondary', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-secondary)]' } },
|
|
60
|
+
{ color: 'success', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-success)]' } },
|
|
61
|
+
{ color: 'info', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-info)]' } },
|
|
62
|
+
{ color: 'warning', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-warning)]' } },
|
|
63
|
+
{ color: 'error', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-error)]' } },
|
|
64
|
+
{ color: 'forest', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-forest)]' } },
|
|
65
|
+
{ color: 'maple', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-maple)]' } },
|
|
66
|
+
{ color: 'river', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-river)]' } },
|
|
67
|
+
{ color: 'warm', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-warm)]' } },
|
|
68
|
+
{ color: 'acid', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-acid)]' } },
|
|
69
|
+
],
|
|
70
|
+
} as const;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forest theme fragment — UInput (text field).
|
|
3
|
+
*
|
|
4
|
+
* Ports the old custom <FInput> "recessed" identity onto the real Nuxt UI <UInput>. The signature is
|
|
5
|
+
* a SOLID inset top line (no blur) that makes the field read as pressed-INTO the page — the exact
|
|
6
|
+
* inverse of the keycap button's raised face. It is the depth effect; everything else is stock.
|
|
7
|
+
*
|
|
8
|
+
* How it composes (important): UInput's resting border and focus border are Tailwind `ring`
|
|
9
|
+
* utilities, which write to `--tw-ring-shadow`. Our depth line is a `shadow-[...]` utility, which
|
|
10
|
+
* writes to `--tw-shadow`. Tailwind merges both into one `box-shadow`, so the inset line stacks
|
|
11
|
+
* UNDER the ring border + focus ring — just like FInput layered an inset line under its 1px border.
|
|
12
|
+
*
|
|
13
|
+
* Forest opinions:
|
|
14
|
+
* - radius ramps w/ size — small fields read proportionally rounder at a fixed radius, so radius
|
|
15
|
+
* climbs with height: xs/sm rounded-sm (8px), md/lg/xl rounded-md (12px).
|
|
16
|
+
* Set per-size in the size variant (NOT the base slot) so one lever owns it. [base slot]
|
|
17
|
+
* - transition — animate box-shadow too (stock only transitions colour) so focus eases in. [base slot]
|
|
18
|
+
* - shadow-[inset…] — `inset 0 var(--forest-input-depth) 0 0 var(--forest-input-recess)`: the
|
|
19
|
+
* recessed depth line, at rest. Depth scales per size (2/2/3/3/4 for
|
|
20
|
+
* xs/sm/md/lg/xl) via the var, set in the size variant, so the shadow itself
|
|
21
|
+
* is written once on the base slot. The colour token is mode-aware
|
|
22
|
+
* (forest.css) so the line stays darker than the field in dark mode
|
|
23
|
+
* instead of reading as a white edge.
|
|
24
|
+
* - focus halo — on focus the resting inset depth line is dropped and replaced by a soft
|
|
25
|
+
* 3px outer halo alone, so the active field reads as lifted-to-focus rather
|
|
26
|
+
* than still pressed-in. The halo colour
|
|
27
|
+
* tracks `color` via --forest-input-halo (the colour variant below):
|
|
28
|
+
* stock only tints the RING, and only on outline/subtle, so a soft or
|
|
29
|
+
* ghost field shows the halo alone and every intent needs its own tone.
|
|
30
|
+
* The --forest-halo-* tokens it points at also flip by mode (forest.css) —
|
|
31
|
+
* numbered ramp steps don't, so one fixed step reads soft on the light
|
|
32
|
+
* page and glares on the dark one.
|
|
33
|
+
* - ghost has no rest — ghost carries no fill and no ring, so a resting depth line floats with
|
|
34
|
+
* nothing to be recessed INTO. It picks the line up on hover/focus, where
|
|
35
|
+
* the elevated fill arrives to hold it. [compoundVariants]
|
|
36
|
+
*
|
|
37
|
+
* Error (color="error" via UFormField) and per-colour focus rings resolve to the Forest ramps
|
|
38
|
+
* automatically through the semantic colour map (maple/forest), so no override is needed for those.
|
|
39
|
+
*
|
|
40
|
+
* Slot names sourced from: apps/docs/node_modules/.nuxt-ui/ui/input.ts
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
export const inputTheme = {
|
|
44
|
+
slots: {
|
|
45
|
+
base: 'transition-[color,box-shadow] duration-(--motion-fast) shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)] focus-visible:shadow-[0_0_0_3px_var(--forest-input-halo,var(--forest-halo-primary))]',
|
|
46
|
+
},
|
|
47
|
+
// Touch: the field is drawn on the TOUCH ladder (min-h 28/36/40/44/52 for xs→xl, vs the fine-pointer
|
|
48
|
+
// 24/28/32/36/40) whenever it is being touched or is baked for touch — `touch:`, the styles/forest.css
|
|
49
|
+
// custom variant, NOT the built-in `pointer-coarse:`. Each size keeps its own rung, so lg is 44 (Apple's
|
|
50
|
+
// min target) and xl 52: a LADDER SWAP, not a shift to the next size up, which is why xl has somewhere
|
|
51
|
+
// to go. It scales as a UNIT (height, padding, gap, radius, icon, type, recess) so it reads as a bigger
|
|
52
|
+
// version of itself, not the same box stretched taller with stranded small type — a flat min-height
|
|
53
|
+
// floor was rejected for exactly that (xs at 48px with 12px text looked empty). Button and badge carry
|
|
54
|
+
// the same rungs, so a mixed <UFieldGroup> stays flush on either ladder.
|
|
55
|
+
//
|
|
56
|
+
// Two things it deliberately does NOT bump, and why:
|
|
57
|
+
// · Horizontal padding (px): stock adds a fixed `ps-9`/`pe-9` when a leading/trailing icon is
|
|
58
|
+
// present, and a `touch:px-*` (padding-inline) emitted after it clobbers that inset — the
|
|
59
|
+
// native `type=file` button then slides under the icon. Width contributes ~nothing to a tap
|
|
60
|
+
// target, so the step holds px and moves py.
|
|
61
|
+
// · Naive base type: stock hangs a RESPONSIVE `md:text-*` shrink per size (a `fixed:false`
|
|
62
|
+
// compound — a size's EFFECTIVE desktop type is one step below its base token). A raw
|
|
63
|
+
// `touch:text-base/5` ignores that and wins at desktop, so a bumped `sm` outgrew its sibling
|
|
64
|
+
// `md` and the ladder inverted. The type step therefore targets the next size's EFFECTIVE value
|
|
65
|
+
// (sm→md `touch:text-sm` 14/20, lg→xl `touch:text-base` 16/24), line-height riding along so
|
|
66
|
+
// the type-driven steps also gain height. Ladder stays monotonic AND every step grows.
|
|
67
|
+
//
|
|
68
|
+
// The recessed depth line scales per size too (shallower on short fields, deeper on tall) and steps
|
|
69
|
+
// with the rest of the bundle. PER-SIZE RADIUS climbs so no size reads over-rounded: xs/sm rounded-sm
|
|
70
|
+
// (8px); md/lg/xl keep stock's base rounded-md (12px) — only xs/sm are overridden, md+ are not
|
|
71
|
+
// restated. Each size lists only its deltas up. The mobile cut ALSO defaults to a bigger `size` (lg
|
|
72
|
+
// via forestMobileProps), so the two effects compound there: bigger rung values AND a bigger default
|
|
73
|
+
// rung, which is what makes the bold cut read as a real touch surface.
|
|
74
|
+
variants: {
|
|
75
|
+
size: {
|
|
76
|
+
// `touch:` = the shared TOUCH ladder (styles/forest.css), the height+type twin of button.ts so a
|
|
77
|
+
// joined <UFieldGroup> matches. min-h is the height authority (28/36/40/44/52 — stock input is
|
|
78
|
+
// padding-driven with no h-*, so min-h floors it and the text centres). text-* is PINNED (not left
|
|
79
|
+
// to the stock base) because stock md/lg run text-base/5 with a responsive desktop shrink — a plain
|
|
80
|
+
// class would flip between the desktop mock (≥768: shrunk) and a real phone (base). Every `touch:`
|
|
81
|
+
// branch is a 2-class selector for exactly that reason, so it outranks the shrink and the size is
|
|
82
|
+
// identical on both, equalling the button's text (xs12·sm14·md14·lg16·xl18). Depth/radius/icon
|
|
83
|
+
// step with the bigger box.
|
|
84
|
+
xs: { base: 'rounded-sm [--forest-input-depth:2px] touch:min-h-7 touch:gap-1.5' },
|
|
85
|
+
sm: { base: 'rounded-sm [--forest-input-depth:2px] touch:min-h-9 touch:text-sm touch:rounded-md touch:[--forest-input-depth:3px]', leadingIcon: 'touch:size-5', trailingIcon: 'touch:size-5' },
|
|
86
|
+
md: { base: '[--forest-input-depth:3px] touch:min-h-10 touch:text-sm touch:gap-2' },
|
|
87
|
+
lg: { base: '[--forest-input-depth:3px] touch:min-h-11 touch:text-base touch:rounded-lg touch:[--forest-input-depth:4px]', leadingIcon: 'touch:size-6', trailingIcon: 'touch:size-6' },
|
|
88
|
+
xl: { base: '[--forest-input-depth:4px] touch:min-h-13 touch:text-lg touch:rounded-lg touch:[--forest-input-depth:4px]', leadingIcon: 'touch:size-7', trailingIcon: 'touch:size-7' },
|
|
89
|
+
},
|
|
90
|
+
// The focus halo follows `color`. Stock only pairs colour with the RING (and only on the ringed
|
|
91
|
+
// variants); the halo is ours, so without this an error field wore a maple ring and a forest
|
|
92
|
+
// green glow. Each colour re-points the halo var at its own 200 step — primary resolves to the
|
|
93
|
+
// same value the hardcoded --forest-200 did, so the default field is unchanged.
|
|
94
|
+
//
|
|
95
|
+
// FLAT strings, not { base: … } objects — stock's colour variant is flat (every entry is ""),
|
|
96
|
+
// and a shape mismatch makes the merge drop these silently. Same trap as the FieldGroup ring bug:
|
|
97
|
+
// match the stock recipe's shape.
|
|
98
|
+
// Halo (focus glow) follows every colour. The recess is NOT set here — `color` alone leaves a
|
|
99
|
+
// resting field neutral (its border is ring-accented; the intent only shows on the focus/highlight
|
|
100
|
+
// ring), so a coloured recess at plain rest would contradict the neutral border. The recess tint is
|
|
101
|
+
// gated to `highlight` in compoundVariants below, where the ring IS persistently coloured.
|
|
102
|
+
color: {
|
|
103
|
+
primary: '[--forest-input-halo:var(--forest-halo-primary)]',
|
|
104
|
+
secondary: '[--forest-input-halo:var(--forest-halo-secondary)]',
|
|
105
|
+
success: '[--forest-input-halo:var(--forest-halo-success)]',
|
|
106
|
+
info: '[--forest-input-halo:var(--forest-halo-info)]',
|
|
107
|
+
warning: '[--forest-input-halo:var(--forest-halo-warning)]',
|
|
108
|
+
error: '[--forest-input-halo:var(--forest-halo-error)]',
|
|
109
|
+
forest: '[--forest-input-halo:var(--forest-halo-forest)]',
|
|
110
|
+
maple: '[--forest-input-halo:var(--forest-halo-maple)]',
|
|
111
|
+
river: '[--forest-input-halo:var(--forest-halo-river)]',
|
|
112
|
+
warm: '[--forest-input-halo:var(--forest-halo-warm)]',
|
|
113
|
+
acid: '[--forest-input-halo:var(--forest-halo-acid)]',
|
|
114
|
+
neutral: '[--forest-input-halo:var(--forest-halo-neutral)]',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
// Ghost drops the resting depth line: with no fill and no ring there is no surface for the field to
|
|
118
|
+
// be recessed into, so the line reads as a stray mark. Hover brings the elevated fill (stock ghost
|
|
119
|
+
// behaviour) and the line with it; focus keeps the base slot's line + halo.
|
|
120
|
+
compoundVariants: [
|
|
121
|
+
{
|
|
122
|
+
variant: 'ghost',
|
|
123
|
+
class: {
|
|
124
|
+
// No fill at rest → no depth line and no focus halo (nothing for either to sit on/behind);
|
|
125
|
+
// hover/focus bring the elevated fill and the depth line back. The halo is dropped in both.
|
|
126
|
+
base: 'shadow-none focus-visible:shadow-none hover:shadow-[inset_0_calc(var(--forest-input-depth)_+_var(--forest-field-edge,0px))_0_0_var(--forest-input-recess)]',
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
// none is fill-less in every state (a bare field, e.g. a select-menu's panel search box) — drop
|
|
130
|
+
// the depth line AND the focus halo so it reads as a plain flush input, not a recessed glowing one.
|
|
131
|
+
{ variant: 'none', class: { base: 'shadow-none focus-visible:shadow-none' } },
|
|
132
|
+
// Recess tint gated to `highlight` (the persistent coloured-ring state) — the ONLY resting state
|
|
133
|
+
// where the intent shows on the border, so the depth line reads as the same accent, not a stray
|
|
134
|
+
// colour on an otherwise-neutral field. neutral is omitted — its highlight ring is the inverted
|
|
135
|
+
// tone, which the neutral recess line already matches.
|
|
136
|
+
{ color: 'primary', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-primary)]' } },
|
|
137
|
+
{ color: 'secondary', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-secondary)]' } },
|
|
138
|
+
{ color: 'success', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-success)]' } },
|
|
139
|
+
{ color: 'info', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-info)]' } },
|
|
140
|
+
{ color: 'warning', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-warning)]' } },
|
|
141
|
+
{ color: 'error', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-error)]' } },
|
|
142
|
+
{ color: 'forest', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-forest)]' } },
|
|
143
|
+
{ color: 'maple', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-maple)]' } },
|
|
144
|
+
{ color: 'river', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-river)]' } },
|
|
145
|
+
{ color: 'warm', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-warm)]' } },
|
|
146
|
+
{ color: 'acid', highlight: true, class: { base: '[--forest-input-recess:var(--forest-recess-acid)]' } },
|
|
147
|
+
],
|
|
148
|
+
} as const;
|