@texturehq/edges 2.4.6 → 2.4.7

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.
@@ -2117,6 +2117,71 @@ declare const TextLink: ({ href, children, className, external, title, variant,
2117
2117
  /** Grouping for an entity. Lets surfaces section grid elements and devices
2118
2118
  * apart from core platform objects. */
2119
2119
  type EntityCategory = "platform" | "grid" | "device";
2120
+ /**
2121
+ * The base page composition an entity renders with. Thirty in-scope entities
2122
+ * share these five compositions — the per-entity variation is which blocks
2123
+ * appear (driven by this config), not per-entity page code.
2124
+ *
2125
+ * - `device` — Battery, EV Charger, Inverter, Thermostat, EV, Water Heater.
2126
+ * Leads with `entity.now` (live state + headline metrics).
2127
+ * - `platform` — Site, Customer. No `Now` block.
2128
+ * - `grid-energized` — energized grid equipment (Transformer, Recloser, Meter…).
2129
+ * - `grid-line` — lines & structures (overhead/underground spans, support structures).
2130
+ *
2131
+ * Matches the design's coverage matrix (DESIGN-REFERENCE.md §2). Every entry in
2132
+ * `ENTITY_CONFIG` carries an archetype, even the 12 that have no detail page —
2133
+ * the archetype is the composition it *would* use; `detailPage` gates whether a
2134
+ * page is actually reachable.
2135
+ */
2136
+ type EntityArchetype = "device" | "platform" | "grid-energized" | "grid-line";
2137
+ /**
2138
+ * A serializable `FieldFormat`. `entity.now` and every block that consumes a
2139
+ * config must be JSON-serializable (the core block contract forbids functions
2140
+ * in props), so the function-carrying `custom` format variant is excluded here
2141
+ * at the type level — a metric can never smuggle a `formatter` into the registry.
2142
+ */
2143
+ type SerializableFieldFormat = Exclude<FieldFormat, {
2144
+ type: "custom";
2145
+ }>;
2146
+ /**
2147
+ * One headline metric shown by `entity.now`. A serializable declaration only —
2148
+ * `path` is a dot-path into the resolved entity data, `label` is a translation
2149
+ * key, `format` says how to render the value, and `icon` is a registry key
2150
+ * (never a component). No functions: the host resolves `path`/`format` at render.
2151
+ *
2152
+ * The shape is the serializable subset of `device-config`'s `FieldConfig`
2153
+ * (`id`/`label`/`path`/`format`/`icon`) — `showWhen`/`resolver`/`custom`
2154
+ * formatters are intentionally dropped.
2155
+ */
2156
+ interface HeadlineMetric {
2157
+ /** Stable identifier for the metric (unique within an entity). */
2158
+ id: string;
2159
+ /** Translation key for the display label. */
2160
+ label: string;
2161
+ /** Dot-path into the resolved entity data (e.g. "state.gridPower"). */
2162
+ path: string;
2163
+ /** How to render the value. Serializable formats only. */
2164
+ format: SerializableFieldFormat;
2165
+ /** Optional icon registry key. */
2166
+ icon?: IconName;
2167
+ }
2168
+ /**
2169
+ * A serializable rule for deriving a display state from resolved entity data.
2170
+ * Mirrors `device-config`'s `StateRule` but drops the optional `resolver`
2171
+ * function so the registry stays JSON-serializable. `mapping` maps a raw field
2172
+ * value to a display-state token; `fallback` is used when the field is
2173
+ * missing/unmapped.
2174
+ */
2175
+ interface EntityStateRule {
2176
+ /** Dot-path to the source field in the resolved entity data. */
2177
+ fieldPath: string;
2178
+ /** Raw-value → display-state-token map. */
2179
+ mapping: Record<string, string>;
2180
+ /** State token to use when the field is missing or unmapped. */
2181
+ fallback: string;
2182
+ /** Optional translation key for the state's display label. */
2183
+ label?: string;
2184
+ }
2120
2185
  interface EntityConfig {
2121
2186
  /** Phosphor icon name. The canonical (resting / default) glyph. For switchable
2122
2187
  * elements this mirrors `states.closed.icon` (or the base glyph when the
@@ -2145,6 +2210,40 @@ interface EntityConfig {
2145
2210
  open: EntityStateVariant;
2146
2211
  closed: EntityStateVariant;
2147
2212
  };
2213
+ /**
2214
+ * The base page composition this entity renders with. Required on all 42
2215
+ * entries — the archetype is the composition an entity *would* use even when
2216
+ * `detailPage` is false.
2217
+ */
2218
+ archetype: EntityArchetype;
2219
+ /**
2220
+ * Whether this entity has a reachable detail page. 30 of 42 are `true`; the
2221
+ * registry is the single answer to "does this entity have a page?".
2222
+ */
2223
+ detailPage: boolean;
2224
+ /**
2225
+ * `entity.now` field config. Present only for entities that show a `Now`
2226
+ * block (devices with a `device-config` source, plus Meter). Absent means
2227
+ * `entity.now` declines to render — grid elements omit this until the design's
2228
+ * (currently "For review") metric proposal is approved, and Site/Customer
2229
+ * omit it because their composition has no `Now` block.
2230
+ */
2231
+ fields?: {
2232
+ /**
2233
+ * The 2–4 headline metrics `entity.now` shows. The cell count adapts across
2234
+ * that range; the bound is enforced by the conformance test, not just docs.
2235
+ */
2236
+ headlineMetrics: HeadlineMetric[];
2237
+ };
2238
+ /**
2239
+ * State rules for `entity.now`'s status chips. `primaryState` drives the
2240
+ * pulsing primary chip; `secondaryState` (battery/inverter: charge + grid)
2241
+ * renders a second chip with no pulse.
2242
+ */
2243
+ stateRules?: {
2244
+ primaryState: EntityStateRule;
2245
+ secondaryState?: EntityStateRule;
2246
+ };
2148
2247
  }
2149
2248
  /** One open/closed state's presentation: an optional glyph override and/or a
2150
2249
  * status color. Omitting `icon` means "use the entity's base icon, recolored". */
@@ -2204,6 +2303,8 @@ declare const ENTITY_CONFIG: {
2204
2303
  readonly app: {
2205
2304
  readonly icon: "AppWindow";
2206
2305
  readonly category: "platform";
2306
+ readonly archetype: "platform";
2307
+ readonly detailPage: false;
2207
2308
  readonly label: {
2208
2309
  readonly singular: "App";
2209
2310
  readonly plural: "Apps";
@@ -2213,6 +2314,8 @@ declare const ENTITY_CONFIG: {
2213
2314
  readonly site: {
2214
2315
  readonly icon: "MapPin";
2215
2316
  readonly category: "platform";
2317
+ readonly archetype: "platform";
2318
+ readonly detailPage: true;
2216
2319
  readonly label: {
2217
2320
  readonly singular: "Site";
2218
2321
  readonly plural: "Sites";
@@ -2222,6 +2325,8 @@ declare const ENTITY_CONFIG: {
2222
2325
  readonly device: {
2223
2326
  readonly icon: "ShareNetwork";
2224
2327
  readonly category: "platform";
2328
+ readonly archetype: "platform";
2329
+ readonly detailPage: false;
2225
2330
  readonly label: {
2226
2331
  readonly singular: "Device";
2227
2332
  readonly plural: "Devices";
@@ -2231,6 +2336,8 @@ declare const ENTITY_CONFIG: {
2231
2336
  readonly customer: {
2232
2337
  readonly icon: "Users";
2233
2338
  readonly category: "platform";
2339
+ readonly archetype: "platform";
2340
+ readonly detailPage: true;
2234
2341
  readonly label: {
2235
2342
  readonly singular: "Customer";
2236
2343
  readonly plural: "Customers";
@@ -2240,6 +2347,8 @@ declare const ENTITY_CONFIG: {
2240
2347
  readonly contact: {
2241
2348
  readonly icon: "Users";
2242
2349
  readonly category: "platform";
2350
+ readonly archetype: "platform";
2351
+ readonly detailPage: false;
2243
2352
  readonly label: {
2244
2353
  readonly singular: "Contact";
2245
2354
  readonly plural: "Contacts";
@@ -2249,6 +2358,8 @@ declare const ENTITY_CONFIG: {
2249
2358
  readonly program: {
2250
2359
  readonly icon: "ClipboardText";
2251
2360
  readonly category: "platform";
2361
+ readonly archetype: "platform";
2362
+ readonly detailPage: false;
2252
2363
  readonly label: {
2253
2364
  readonly singular: "Program";
2254
2365
  readonly plural: "Programs";
@@ -2258,6 +2369,8 @@ declare const ENTITY_CONFIG: {
2258
2369
  readonly workflow: {
2259
2370
  readonly icon: "FlowArrow";
2260
2371
  readonly category: "platform";
2372
+ readonly archetype: "platform";
2373
+ readonly detailPage: false;
2261
2374
  readonly label: {
2262
2375
  readonly singular: "Workflow";
2263
2376
  readonly plural: "Workflows";
@@ -2267,6 +2380,8 @@ declare const ENTITY_CONFIG: {
2267
2380
  readonly collection: {
2268
2381
  readonly icon: "Stack";
2269
2382
  readonly category: "platform";
2383
+ readonly archetype: "platform";
2384
+ readonly detailPage: false;
2270
2385
  readonly label: {
2271
2386
  readonly singular: "Collection";
2272
2387
  readonly plural: "Collections";
@@ -2276,6 +2391,8 @@ declare const ENTITY_CONFIG: {
2276
2391
  readonly board: {
2277
2392
  readonly icon: "SquaresFour";
2278
2393
  readonly category: "platform";
2394
+ readonly archetype: "platform";
2395
+ readonly detailPage: false;
2279
2396
  readonly label: {
2280
2397
  readonly singular: "Board";
2281
2398
  readonly plural: "Boards";
@@ -2285,6 +2402,8 @@ declare const ENTITY_CONFIG: {
2285
2402
  readonly report: {
2286
2403
  readonly icon: "ChartLine";
2287
2404
  readonly category: "platform";
2405
+ readonly archetype: "platform";
2406
+ readonly detailPage: false;
2288
2407
  readonly label: {
2289
2408
  readonly singular: "Report";
2290
2409
  readonly plural: "Reports";
@@ -2294,6 +2413,8 @@ declare const ENTITY_CONFIG: {
2294
2413
  readonly event: {
2295
2414
  readonly icon: "ClockCounterClockwise";
2296
2415
  readonly category: "platform";
2416
+ readonly archetype: "platform";
2417
+ readonly detailPage: false;
2297
2418
  readonly label: {
2298
2419
  readonly singular: "Event";
2299
2420
  readonly plural: "Events";
@@ -2303,6 +2424,8 @@ declare const ENTITY_CONFIG: {
2303
2424
  readonly alert: {
2304
2425
  readonly icon: "Warning";
2305
2426
  readonly category: "platform";
2427
+ readonly archetype: "platform";
2428
+ readonly detailPage: false;
2306
2429
  readonly label: {
2307
2430
  readonly singular: "Alert";
2308
2431
  readonly plural: "Alerts";
@@ -2312,6 +2435,8 @@ declare const ENTITY_CONFIG: {
2312
2435
  readonly monitor: {
2313
2436
  readonly icon: "Pulse";
2314
2437
  readonly category: "platform";
2438
+ readonly archetype: "platform";
2439
+ readonly detailPage: false;
2315
2440
  readonly label: {
2316
2441
  readonly singular: "Monitor";
2317
2442
  readonly plural: "Monitors";
@@ -2321,6 +2446,8 @@ declare const ENTITY_CONFIG: {
2321
2446
  readonly command: {
2322
2447
  readonly icon: "Play";
2323
2448
  readonly category: "platform";
2449
+ readonly archetype: "platform";
2450
+ readonly detailPage: false;
2324
2451
  readonly label: {
2325
2452
  readonly singular: "Command";
2326
2453
  readonly plural: "Commands";
@@ -2330,6 +2457,8 @@ declare const ENTITY_CONFIG: {
2330
2457
  readonly source: {
2331
2458
  readonly icon: "TextureSource";
2332
2459
  readonly category: "grid";
2460
+ readonly archetype: "grid-energized";
2461
+ readonly detailPage: true;
2333
2462
  readonly label: {
2334
2463
  readonly singular: "Source";
2335
2464
  readonly plural: "Sources";
@@ -2339,6 +2468,8 @@ declare const ENTITY_CONFIG: {
2339
2468
  readonly substation: {
2340
2469
  readonly icon: "TextureSource";
2341
2470
  readonly category: "grid";
2471
+ readonly archetype: "grid-energized";
2472
+ readonly detailPage: true;
2342
2473
  readonly label: {
2343
2474
  readonly singular: "Substation";
2344
2475
  readonly plural: "Substations";
@@ -2348,6 +2479,8 @@ declare const ENTITY_CONFIG: {
2348
2479
  readonly capacitor: {
2349
2480
  readonly icon: "TextureCapacitor";
2350
2481
  readonly category: "grid";
2482
+ readonly archetype: "grid-energized";
2483
+ readonly detailPage: true;
2351
2484
  readonly label: {
2352
2485
  readonly singular: "Capacitor";
2353
2486
  readonly plural: "Capacitors";
@@ -2357,6 +2490,8 @@ declare const ENTITY_CONFIG: {
2357
2490
  readonly switch: {
2358
2491
  readonly icon: "TextureSwitchClosed";
2359
2492
  readonly category: "grid";
2493
+ readonly archetype: "grid-energized";
2494
+ readonly detailPage: true;
2360
2495
  readonly label: {
2361
2496
  readonly singular: "Switch";
2362
2497
  readonly plural: "Switches";
@@ -2376,6 +2511,8 @@ declare const ENTITY_CONFIG: {
2376
2511
  readonly sectionalizer: {
2377
2512
  readonly icon: "TextureSectionalizerClosed";
2378
2513
  readonly category: "grid";
2514
+ readonly archetype: "grid-energized";
2515
+ readonly detailPage: true;
2379
2516
  readonly label: {
2380
2517
  readonly singular: "Sectionalizer";
2381
2518
  readonly plural: "Sectionalizers";
@@ -2395,6 +2532,8 @@ declare const ENTITY_CONFIG: {
2395
2532
  readonly relay: {
2396
2533
  readonly icon: "Cpu";
2397
2534
  readonly category: "grid";
2535
+ readonly archetype: "grid-energized";
2536
+ readonly detailPage: true;
2398
2537
  readonly label: {
2399
2538
  readonly singular: "Relay";
2400
2539
  readonly plural: "Relays";
@@ -2404,6 +2543,8 @@ declare const ENTITY_CONFIG: {
2404
2543
  readonly transformer: {
2405
2544
  readonly icon: "TextureTransformer";
2406
2545
  readonly category: "grid";
2546
+ readonly archetype: "grid-energized";
2547
+ readonly detailPage: true;
2407
2548
  readonly label: {
2408
2549
  readonly singular: "Transformer";
2409
2550
  readonly plural: "Transformers";
@@ -2413,15 +2554,42 @@ declare const ENTITY_CONFIG: {
2413
2554
  readonly meter: {
2414
2555
  readonly icon: "Gauge";
2415
2556
  readonly category: "grid";
2557
+ readonly archetype: "grid-energized";
2558
+ readonly detailPage: true;
2416
2559
  readonly label: {
2417
2560
  readonly singular: "Meter";
2418
2561
  readonly plural: "Meters";
2419
2562
  };
2420
2563
  readonly description: "Revenue meter at the point of consumption";
2564
+ readonly fields: {
2565
+ readonly headlineMetrics: [{
2566
+ readonly id: "power";
2567
+ readonly label: "device.meter.fields.power";
2568
+ readonly path: "state.phaseARealPower";
2569
+ readonly format: {
2570
+ readonly type: "power";
2571
+ readonly unit: "kW";
2572
+ readonly decimals: 2;
2573
+ };
2574
+ readonly icon: "Pulse";
2575
+ }, {
2576
+ readonly id: "consumption";
2577
+ readonly label: "device.meter.fields.consumption";
2578
+ readonly path: "state.latestKwhUsage";
2579
+ readonly format: {
2580
+ readonly type: "energy";
2581
+ readonly sourceUnit: "kWh";
2582
+ readonly decimals: 2;
2583
+ };
2584
+ readonly icon: "Lightning";
2585
+ }];
2586
+ };
2421
2587
  };
2422
2588
  readonly consumer: {
2423
2589
  readonly icon: "Gauge";
2424
2590
  readonly category: "grid";
2591
+ readonly archetype: "grid-energized";
2592
+ readonly detailPage: true;
2425
2593
  readonly label: {
2426
2594
  readonly singular: "Consumer";
2427
2595
  readonly plural: "Consumers";
@@ -2431,6 +2599,8 @@ declare const ENTITY_CONFIG: {
2431
2599
  readonly singlePhaseOverheadLine: {
2432
2600
  readonly icon: "TextureSinglePhaseOverheadLine";
2433
2601
  readonly category: "grid";
2602
+ readonly archetype: "grid-line";
2603
+ readonly detailPage: true;
2434
2604
  readonly label: {
2435
2605
  readonly singular: "Single-Phase Overhead Line";
2436
2606
  readonly plural: "Single-Phase Overhead Lines";
@@ -2440,6 +2610,8 @@ declare const ENTITY_CONFIG: {
2440
2610
  readonly twoPhaseOverheadLine: {
2441
2611
  readonly icon: "TextureTwoPhaseOverheadLine";
2442
2612
  readonly category: "grid";
2613
+ readonly archetype: "grid-line";
2614
+ readonly detailPage: true;
2443
2615
  readonly label: {
2444
2616
  readonly singular: "Two-Phase Overhead Line";
2445
2617
  readonly plural: "Two-Phase Overhead Lines";
@@ -2449,6 +2621,8 @@ declare const ENTITY_CONFIG: {
2449
2621
  readonly threePhaseOverheadLine: {
2450
2622
  readonly icon: "TextureThreePhaseOverheadLine";
2451
2623
  readonly category: "grid";
2624
+ readonly archetype: "grid-line";
2625
+ readonly detailPage: true;
2452
2626
  readonly label: {
2453
2627
  readonly singular: "Three-Phase Overhead Line";
2454
2628
  readonly plural: "Three-Phase Overhead Lines";
@@ -2458,6 +2632,8 @@ declare const ENTITY_CONFIG: {
2458
2632
  readonly singlePhaseUndergroundLine: {
2459
2633
  readonly icon: "TextureSinglePhaseUndergroundLine";
2460
2634
  readonly category: "grid";
2635
+ readonly archetype: "grid-line";
2636
+ readonly detailPage: true;
2461
2637
  readonly label: {
2462
2638
  readonly singular: "Single-Phase Underground Line";
2463
2639
  readonly plural: "Single-Phase Underground Lines";
@@ -2467,6 +2643,8 @@ declare const ENTITY_CONFIG: {
2467
2643
  readonly twoPhaseUndergroundLine: {
2468
2644
  readonly icon: "TextureTwoPhaseUndergroundLine";
2469
2645
  readonly category: "grid";
2646
+ readonly archetype: "grid-line";
2647
+ readonly detailPage: true;
2470
2648
  readonly label: {
2471
2649
  readonly singular: "Two-Phase Underground Line";
2472
2650
  readonly plural: "Two-Phase Underground Lines";
@@ -2476,6 +2654,8 @@ declare const ENTITY_CONFIG: {
2476
2654
  readonly threePhaseUndergroundLine: {
2477
2655
  readonly icon: "TextureThreePhaseUndergroundLine";
2478
2656
  readonly category: "grid";
2657
+ readonly archetype: "grid-line";
2658
+ readonly detailPage: true;
2479
2659
  readonly label: {
2480
2660
  readonly singular: "Three-Phase Underground Line";
2481
2661
  readonly plural: "Three-Phase Underground Lines";
@@ -2485,6 +2665,8 @@ declare const ENTITY_CONFIG: {
2485
2665
  readonly motorSwitch: {
2486
2666
  readonly icon: "Diamond";
2487
2667
  readonly category: "grid";
2668
+ readonly archetype: "grid-energized";
2669
+ readonly detailPage: true;
2488
2670
  readonly label: {
2489
2671
  readonly singular: "Motor Switch";
2490
2672
  readonly plural: "Motor Switches";
@@ -2494,6 +2676,8 @@ declare const ENTITY_CONFIG: {
2494
2676
  readonly recloser: {
2495
2677
  readonly icon: "TextureRecloser";
2496
2678
  readonly category: "grid";
2679
+ readonly archetype: "grid-energized";
2680
+ readonly detailPage: true;
2497
2681
  readonly label: {
2498
2682
  readonly singular: "Recloser";
2499
2683
  readonly plural: "Reclosers";
@@ -2511,6 +2695,8 @@ declare const ENTITY_CONFIG: {
2511
2695
  readonly fuse: {
2512
2696
  readonly icon: "TextureFuse";
2513
2697
  readonly category: "grid";
2698
+ readonly archetype: "grid-energized";
2699
+ readonly detailPage: true;
2514
2700
  readonly label: {
2515
2701
  readonly singular: "Fuse";
2516
2702
  readonly plural: "Fuses";
@@ -2520,6 +2706,8 @@ declare const ENTITY_CONFIG: {
2520
2706
  readonly breaker: {
2521
2707
  readonly icon: "TextureBreaker";
2522
2708
  readonly category: "grid";
2709
+ readonly archetype: "grid-energized";
2710
+ readonly detailPage: true;
2523
2711
  readonly label: {
2524
2712
  readonly singular: "Breaker";
2525
2713
  readonly plural: "Breakers";
@@ -2537,6 +2725,8 @@ declare const ENTITY_CONFIG: {
2537
2725
  readonly generator: {
2538
2726
  readonly icon: "Wind";
2539
2727
  readonly category: "grid";
2728
+ readonly archetype: "grid-energized";
2729
+ readonly detailPage: true;
2540
2730
  readonly label: {
2541
2731
  readonly singular: "Generator";
2542
2732
  readonly plural: "Generators";
@@ -2546,6 +2736,8 @@ declare const ENTITY_CONFIG: {
2546
2736
  readonly regulator: {
2547
2737
  readonly icon: "TextureRegulator";
2548
2738
  readonly category: "grid";
2739
+ readonly archetype: "grid-energized";
2740
+ readonly detailPage: true;
2549
2741
  readonly label: {
2550
2742
  readonly singular: "Regulator";
2551
2743
  readonly plural: "Regulators";
@@ -2555,6 +2747,8 @@ declare const ENTITY_CONFIG: {
2555
2747
  readonly supportStructure: {
2556
2748
  readonly icon: "TextureSupportStructure";
2557
2749
  readonly category: "grid";
2750
+ readonly archetype: "grid-line";
2751
+ readonly detailPage: true;
2558
2752
  readonly label: {
2559
2753
  readonly singular: "Support Structure";
2560
2754
  readonly plural: "Support Structures";
@@ -2564,51 +2758,256 @@ declare const ENTITY_CONFIG: {
2564
2758
  readonly battery: {
2565
2759
  readonly icon: "BatteryHigh";
2566
2760
  readonly category: "device";
2761
+ readonly archetype: "device";
2762
+ readonly detailPage: true;
2567
2763
  readonly label: {
2568
2764
  readonly singular: "Battery";
2569
2765
  readonly plural: "Batteries";
2570
2766
  };
2571
2767
  readonly description: "Behind-the-meter battery or storage system";
2768
+ readonly fields: {
2769
+ readonly headlineMetrics: [{
2770
+ readonly id: "power";
2771
+ readonly label: "device.battery.fields.power";
2772
+ readonly path: "state.gridPower";
2773
+ readonly format: {
2774
+ readonly type: "power";
2775
+ readonly decimals: 1;
2776
+ };
2777
+ readonly icon: "Lightning";
2778
+ }, {
2779
+ readonly id: "soc";
2780
+ readonly label: "device.battery.fields.soc";
2781
+ readonly path: "state.chargePercentage";
2782
+ readonly format: {
2783
+ readonly type: "percentage";
2784
+ readonly decimals: 0;
2785
+ };
2786
+ readonly icon: "BatteryCharging";
2787
+ }];
2788
+ };
2789
+ readonly stateRules: {
2790
+ readonly primaryState: {
2791
+ readonly label: "device.battery.fields.status";
2792
+ readonly fieldPath: "state.chargingState";
2793
+ readonly mapping: {
2794
+ readonly charging: "charging";
2795
+ readonly discharging: "discharging";
2796
+ readonly idle: "idle";
2797
+ readonly unknown: "unknown";
2798
+ };
2799
+ readonly fallback: "unknown";
2800
+ };
2801
+ readonly secondaryState: {
2802
+ readonly label: "device.battery.fields.gridState";
2803
+ readonly fieldPath: "state.gridStatus";
2804
+ readonly mapping: {
2805
+ readonly importing: "importing";
2806
+ readonly exporting: "exporting";
2807
+ readonly idle: "importing";
2808
+ readonly unknown: "importing";
2809
+ };
2810
+ readonly fallback: "importing";
2811
+ };
2812
+ };
2572
2813
  };
2573
2814
  readonly evCharger: {
2574
2815
  readonly icon: "ChargingStation";
2575
2816
  readonly category: "device";
2817
+ readonly archetype: "device";
2818
+ readonly detailPage: true;
2576
2819
  readonly label: {
2577
2820
  readonly singular: "EV Charger";
2578
2821
  readonly plural: "EV Chargers";
2579
2822
  };
2580
2823
  readonly description: "Electric-vehicle charging station or port";
2824
+ readonly fields: {
2825
+ readonly headlineMetrics: [{
2826
+ readonly id: "power";
2827
+ readonly label: "device.evCharger.fields.power";
2828
+ readonly path: "state.chargerWattage";
2829
+ readonly format: {
2830
+ readonly type: "power";
2831
+ readonly decimals: 1;
2832
+ };
2833
+ readonly icon: "Lightning";
2834
+ }, {
2835
+ readonly id: "isPluggedIn";
2836
+ readonly label: "device.evCharger.fields.isPluggedIn";
2837
+ readonly path: "state.isPluggedIn";
2838
+ readonly format: {
2839
+ readonly type: "boolean";
2840
+ readonly trueText: "Yes";
2841
+ readonly falseText: "No";
2842
+ };
2843
+ readonly icon: "Plug";
2844
+ }];
2845
+ };
2846
+ readonly stateRules: {
2847
+ readonly primaryState: {
2848
+ readonly label: "device.evCharger.fields.status";
2849
+ readonly fieldPath: "state.chargingState";
2850
+ readonly mapping: {
2851
+ readonly charging: "charging";
2852
+ readonly discharging: "discharging";
2853
+ readonly idle: "idle";
2854
+ readonly unknown: "unknown";
2855
+ };
2856
+ readonly fallback: "unknown";
2857
+ };
2858
+ };
2581
2859
  };
2582
2860
  readonly inverter: {
2583
2861
  readonly icon: "Sun";
2584
2862
  readonly category: "device";
2863
+ readonly archetype: "device";
2864
+ readonly detailPage: true;
2585
2865
  readonly label: {
2586
2866
  readonly singular: "Solar / Inverter";
2587
2867
  readonly plural: "Solar / Inverters";
2588
2868
  };
2589
2869
  readonly description: "Solar PV inverter and its connected array";
2870
+ readonly fields: {
2871
+ readonly headlineMetrics: [{
2872
+ readonly id: "power";
2873
+ readonly label: "device.inverter.fields.power";
2874
+ readonly path: "state.power";
2875
+ readonly format: {
2876
+ readonly type: "power";
2877
+ readonly decimals: 0;
2878
+ };
2879
+ readonly icon: "Lightning";
2880
+ }, {
2881
+ readonly id: "gridPower";
2882
+ readonly label: "device.inverter.fields.gridPower";
2883
+ readonly path: "state.gridPower";
2884
+ readonly format: {
2885
+ readonly type: "power";
2886
+ readonly decimals: 0;
2887
+ };
2888
+ readonly icon: "GridFour";
2889
+ }];
2890
+ };
2891
+ readonly stateRules: {
2892
+ readonly primaryState: {
2893
+ readonly label: "device.inverter.fields.gridStatus";
2894
+ readonly fieldPath: "state.gridStatus";
2895
+ readonly mapping: {
2896
+ readonly exporting: "exporting";
2897
+ readonly importing: "importing";
2898
+ readonly idle: "idle";
2899
+ };
2900
+ readonly fallback: "unknown";
2901
+ };
2902
+ };
2590
2903
  };
2591
2904
  readonly thermostat: {
2592
2905
  readonly icon: "Thermometer";
2593
2906
  readonly category: "device";
2907
+ readonly archetype: "device";
2908
+ readonly detailPage: true;
2594
2909
  readonly label: {
2595
2910
  readonly singular: "Thermostat";
2596
2911
  readonly plural: "Thermostats";
2597
2912
  };
2598
2913
  readonly description: "Smart thermostat or connected HVAC control";
2914
+ readonly fields: {
2915
+ readonly headlineMetrics: [{
2916
+ readonly id: "ambientTemperature";
2917
+ readonly label: "device.thermostat.fields.ambientTemperature";
2918
+ readonly path: "state.ambientTemperature";
2919
+ readonly format: {
2920
+ readonly type: "temperature";
2921
+ readonly decimals: 0;
2922
+ };
2923
+ readonly icon: "Thermometer";
2924
+ }, {
2925
+ readonly id: "heatTarget";
2926
+ readonly label: "device.thermostat.fields.heatTarget";
2927
+ readonly path: "state.heatTarget";
2928
+ readonly format: {
2929
+ readonly type: "temperature";
2930
+ readonly decimals: 0;
2931
+ };
2932
+ readonly icon: "Flame";
2933
+ }, {
2934
+ readonly id: "coolTarget";
2935
+ readonly label: "device.thermostat.fields.coolTarget";
2936
+ readonly path: "state.coolTarget";
2937
+ readonly format: {
2938
+ readonly type: "temperature";
2939
+ readonly decimals: 0;
2940
+ };
2941
+ readonly icon: "Snowflake";
2942
+ }];
2943
+ };
2944
+ readonly stateRules: {
2945
+ readonly primaryState: {
2946
+ readonly label: "device.thermostat.fields.operatingMode";
2947
+ readonly fieldPath: "state.operatingMode";
2948
+ readonly mapping: {
2949
+ readonly heat: "heat";
2950
+ readonly cool: "cool";
2951
+ readonly auto: "auto";
2952
+ readonly off: "off";
2953
+ readonly eco: "eco";
2954
+ readonly unknown: "unknown";
2955
+ };
2956
+ readonly fallback: "unknown";
2957
+ };
2958
+ };
2599
2959
  };
2600
2960
  readonly vehicle: {
2601
2961
  readonly icon: "Car";
2602
2962
  readonly category: "device";
2963
+ readonly archetype: "device";
2964
+ readonly detailPage: true;
2603
2965
  readonly label: {
2604
2966
  readonly singular: "EV";
2605
2967
  readonly plural: "EVs";
2606
2968
  };
2607
2969
  readonly description: "Electric vehicle managed as a flexible load";
2970
+ readonly fields: {
2971
+ readonly headlineMetrics: [{
2972
+ readonly id: "chargePercentage";
2973
+ readonly label: "device.vehicle.fields.chargePercentage";
2974
+ readonly path: "state.chargePercentage";
2975
+ readonly format: {
2976
+ readonly type: "percentage";
2977
+ readonly decimals: 0;
2978
+ };
2979
+ readonly icon: "BatteryCharging";
2980
+ }, {
2981
+ readonly id: "range";
2982
+ readonly label: "device.vehicle.fields.range";
2983
+ readonly path: "state.range";
2984
+ readonly format: {
2985
+ readonly type: "distance";
2986
+ readonly unit: "mi";
2987
+ readonly decimals: 0;
2988
+ };
2989
+ readonly icon: "GasPump";
2990
+ }];
2991
+ };
2992
+ readonly stateRules: {
2993
+ readonly primaryState: {
2994
+ readonly label: "device.vehicle.fields.status";
2995
+ readonly fieldPath: "state.chargingState";
2996
+ readonly mapping: {
2997
+ readonly charging: "charging";
2998
+ readonly discharging: "discharging";
2999
+ readonly idle: "idle";
3000
+ readonly unknown: "unknown";
3001
+ };
3002
+ readonly fallback: "unknown";
3003
+ };
3004
+ };
2608
3005
  };
2609
3006
  readonly waterHeater: {
2610
3007
  readonly icon: "Drop";
2611
3008
  readonly category: "device";
3009
+ readonly archetype: "device";
3010
+ readonly detailPage: true;
2612
3011
  readonly label: {
2613
3012
  readonly singular: "Water Heater";
2614
3013
  readonly plural: "Water Heaters";
@@ -2663,6 +3062,48 @@ declare function getEntityLabel(entityType: EntityType, plural?: boolean): strin
2663
3062
  * @returns The entity's category
2664
3063
  */
2665
3064
  declare function getEntityCategory(entityType: EntityType): EntityCategory;
3065
+ /**
3066
+ * Inclusive bounds on `fields.headlineMetrics`. The design's `entity.now`
3067
+ * acceptance criteria say the cell count adapts across this range. Exported so
3068
+ * the conformance test enforces the bound rather than documenting it.
3069
+ */
3070
+ declare const HEADLINE_METRIC_BOUNDS: {
3071
+ readonly min: 2;
3072
+ readonly max: 4;
3073
+ };
3074
+ /**
3075
+ * Resolve the base page composition for an entity. This is what lets the 30
3076
+ * in-scope entities share five compositions instead of 30 pages of page code.
3077
+ *
3078
+ * @param entityType - The entity type key
3079
+ * @returns The entity's archetype
3080
+ * @throws If `entityType` is not a known entity (never returns `undefined`, so
3081
+ * a typo surfaces as a loud error rather than a silently missing composition).
3082
+ *
3083
+ * @example
3084
+ * ```tsx
3085
+ * archetypeFor("battery"); // "device"
3086
+ * archetypeFor("transformer"); // "grid-energized"
3087
+ * archetypeFor("nope"); // throws
3088
+ * ```
3089
+ */
3090
+ declare function archetypeFor(entityType: EntityType): EntityArchetype;
3091
+ /**
3092
+ * Whether an entity has a reachable detail page. The registry is the single
3093
+ * answer to "does this entity have a page?".
3094
+ *
3095
+ * @param entityType - The entity type key
3096
+ */
3097
+ declare function entityHasDetailPage(entityType: EntityType): boolean;
3098
+ /**
3099
+ * Whether `entity.now` renders a metric grid for this entity. True iff the
3100
+ * entity declares at least one headline metric. Grid elements (no metric
3101
+ * registry yet), Site, Customer and Water Heater return `false` — `entity.now`
3102
+ * declines to render its cells rather than crashing or rendering empty.
3103
+ *
3104
+ * @param entityType - The entity type key
3105
+ */
3106
+ declare function entityShowsNow(entityType: EntityType): boolean;
2666
3107
 
2667
3108
  /**
2668
3109
  * Resolves a CSS variable to its computed color value.
@@ -2723,4 +3164,4 @@ declare const getContrastingTextColor: (backgroundColor: string) => string;
2723
3164
  */
2724
3165
  declare const mapValuesToCategoricalColors: (values: (string | number)[]) => Record<string | number, string>;
2725
3166
 
2726
- export { type DistanceFormat as $, type ActionItem as A, type BadgeProps as B, type ChartMargin as C, getContrastingTextColor as D, ENTITY_CONFIG as E, getDefaultChartColor as F, getDefaultColors as G, Heading as H, type InteractiveMapProps as I, getEntityConfig as J, getEntityIcon as K, Loader as L, type MapPoint as M, getEntityLabel as N, getResolvedColor as O, getThemeCategoricalColors as P, getYFormatSettings as Q, isLightColor as R, type SegmentOption as S, TextLink as T, type FieldValue as U, type BooleanFormat as V, type FormattedValue as W, type FieldFormat as X, type YFormatSettings as Y, type CurrentFormat as Z, type DateFormat as _, type ActionMenuProps as a, type VoltageUnit as a$, type EnergyUnit as a0, type EnergyFormat as a1, type CurrencyFormat as a2, type NumberFormat as a3, type PhoneFormat as a4, type PowerFormat as a5, type FormatterFunction as a6, type ResistanceFormat as a7, type TemperatureFormat as a8, type TemperatureUnitString as a9, ENTITY_CATEGORY_CONFIG as aA, type EntityCategory as aB, type EntityCategoryConfig as aC, GRID_STATE_COLORS as aD, type GridStateColor as aE, InteractiveMap as aF, type InteractiveMapHandle as aG, type LayerFeature as aH, type LayerStyle as aI, MAP_TYPES as aJ, type MapType as aK, Meter as aL, type MetricFormat as aM, type PercentageFormat as aN, type PowerUnit as aO, type RenderType as aP, type ResistanceUnit as aQ, SegmentedControl as aR, StackNav as aS, type StackNavGroup as aT, type StackNavItem as aU, type StackNavLinkComponentProps as aV, type StackNavProps as aW, type StackNavTheme as aX, StaticMap as aY, type TextTransform as aZ, type TextTruncatePosition as a_, type TemperatureUnit as aa, type TextFormat as ab, type VoltageFormat as ac, type DeviceState as ad, type GridState as ae, type ComponentFormatter as af, type LayerSpec as ag, type CustomPinsSpec as ah, type GeoJsonLayerSpec as ai, type RasterLayerSpec as aj, type VectorLayerSpec as ak, type ClusteredVectorLayerSpec as al, ActionMenu as am, AppShell as an, Avatar as ao, Badge as ap, type BaseFormat as aq, ChartContext as ar, CodeEditor as as, type ColorSpec as at, type ComponentFormatOptions as au, type CurrentUnit as av, type CustomFormat as aw, DEFAULT_MAP_TYPE as ax, type DateFormatStyle as ay, type DistanceUnit as az, type AppShellProps as b, type ZoomStops as b0, activeDeviceStates as b1, baselineFromPoint as b2, deviceStateLabels as b3, deviceStateMetricFormats as b4, formatComponentValue as b5, getDeviceStateLabel as b6, getEntityCategory as b7, getGridStateLabel as b8, gridStateLabels as b9, isActiveState as ba, mapValuesToCategoricalColors as bb, useChartContext as bc, useComponentFormatter as bd, type AvatarProps as c, type BaseDataPoint as d, type CodeEditorProps as e, type CodeLanguage as f, type CodeTheme as g, type EntityConfig as h, type EntityType as i, Logo as j, type MeterProps as k, type SegmentedControlProps as l, SideNav as m, type SideNavItem as n, type SideNavProps as o, type StaticMapProps as p, type TooltipData as q, type TooltipSeries as r, TopNav as s, type TopNavProps as t, type YFormatType as u, clearColorCache as v, createCategoryColorMap as w, createXScale as x, createYScale as y, defaultMargin as z };
3167
+ export { getYFormatSettings as $, type ActionItem as A, type BadgeProps as B, type ChartMargin as C, archetypeFor as D, ENTITY_CONFIG as E, clearColorCache as F, createCategoryColorMap as G, HEADLINE_METRIC_BOUNDS as H, type InteractiveMapProps as I, createXScale as J, createYScale as K, Loader as L, type MapPoint as M, defaultMargin as N, entityHasDetailPage as O, entityShowsNow as P, getContrastingTextColor as Q, getDefaultChartColor as R, type SegmentOption as S, TextLink as T, getDefaultColors as U, getEntityConfig as V, getEntityIcon as W, getEntityLabel as X, type YFormatSettings as Y, getResolvedColor as Z, getThemeCategoricalColors as _, type ActionMenuProps as a, type StackNavGroup as a$, isLightColor as a0, type FieldValue as a1, type BooleanFormat as a2, type FormattedValue as a3, type FieldFormat as a4, type CurrentFormat as a5, type DateFormat as a6, type DistanceFormat as a7, type EnergyUnit as a8, type EnergyFormat as a9, CodeEditor as aA, type ColorSpec as aB, type ComponentFormatOptions as aC, type CurrentUnit as aD, type CustomFormat as aE, DEFAULT_MAP_TYPE as aF, type DateFormatStyle as aG, type DistanceUnit as aH, ENTITY_CATEGORY_CONFIG as aI, type EntityCategory as aJ, type EntityCategoryConfig as aK, GRID_STATE_COLORS as aL, type GridStateColor as aM, InteractiveMap as aN, type InteractiveMapHandle as aO, type LayerFeature as aP, type LayerStyle as aQ, MAP_TYPES as aR, type MapType as aS, Meter as aT, type MetricFormat as aU, type PercentageFormat as aV, type PowerUnit as aW, type RenderType as aX, type ResistanceUnit as aY, SegmentedControl as aZ, StackNav as a_, type CurrencyFormat as aa, type NumberFormat as ab, type PhoneFormat as ac, type PowerFormat as ad, type FormatterFunction as ae, type ResistanceFormat as af, type TemperatureFormat as ag, type TemperatureUnitString as ah, type TemperatureUnit as ai, type TextFormat as aj, type VoltageFormat as ak, type DeviceState as al, type GridState as am, type ComponentFormatter as an, type LayerSpec as ao, type CustomPinsSpec as ap, type GeoJsonLayerSpec as aq, type RasterLayerSpec as ar, type VectorLayerSpec as as, type ClusteredVectorLayerSpec as at, ActionMenu as au, AppShell as av, Avatar as aw, Badge as ax, type BaseFormat as ay, ChartContext as az, type AppShellProps as b, type StackNavItem as b0, type StackNavLinkComponentProps as b1, type StackNavProps as b2, type StackNavTheme as b3, StaticMap as b4, type TextTransform as b5, type TextTruncatePosition as b6, type VoltageUnit as b7, type ZoomStops as b8, activeDeviceStates as b9, baselineFromPoint as ba, deviceStateLabels as bb, deviceStateMetricFormats as bc, formatComponentValue as bd, getDeviceStateLabel as be, getEntityCategory as bf, getGridStateLabel as bg, gridStateLabels as bh, isActiveState as bi, mapValuesToCategoricalColors as bj, useChartContext as bk, useComponentFormatter as bl, type AvatarProps as c, type BaseDataPoint as d, type CodeEditorProps as e, type CodeLanguage as f, type CodeTheme as g, type EntityArchetype as h, type EntityConfig as i, type EntityStateRule as j, type EntityType as k, Heading as l, type HeadlineMetric as m, Logo as n, type MeterProps as o, type SegmentedControlProps as p, type SerializableFieldFormat as q, SideNav as r, type SideNavItem as s, type SideNavProps as t, type StaticMapProps as u, type TooltipData as v, type TooltipSeries as w, TopNav as x, type TopNavProps as y, type YFormatType as z };