@norconsult-digital-public/isypixel 2.0.2-canary.3 → 2.0.2-canary.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/LICENSE.md +11 -0
  2. package/dist/docs/web-components/ip-icon-button/llm.md +113 -0
  3. package/dist/docs/web-components/ip-main-menu/llm.md +219 -0
  4. package/dist/docs/web-components/ip-main-menu-group/llm.md +114 -0
  5. package/dist/docs/web-components/ip-main-menu-item/llm.md +104 -0
  6. package/dist/docs/web-components/ip-main-menu-section/llm.md +95 -0
  7. package/dist/docs/web-components/ip-main-menu-toggle/llm.md +106 -0
  8. package/dist/docs/web-components/ip-tooltip/llm.md +170 -0
  9. package/dist/docs/web-components/services/i18n/llm.md +150 -0
  10. package/dist/llm.md +18 -12
  11. package/dist/types/components/ip-icon-button/ip-icon-button.d.ts +11 -1
  12. package/dist/types/components/ip-main-menu/i18n.d.ts +8 -0
  13. package/dist/types/components/ip-main-menu/ip-main-menu-drawer-styles.d.ts +1 -0
  14. package/dist/types/components/ip-main-menu/ip-main-menu-state-store.d.ts +24 -0
  15. package/dist/types/components/ip-main-menu/ip-main-menu.d.ts +81 -0
  16. package/dist/types/components/ip-main-menu-group/ip-main-menu-group.d.ts +20 -0
  17. package/dist/types/components/ip-main-menu-item/ip-main-menu-item.d.ts +21 -0
  18. package/dist/types/components/ip-main-menu-section/ip-main-menu-section.d.ts +7 -0
  19. package/dist/types/components/ip-main-menu-toggle/i18n.d.ts +4 -0
  20. package/dist/types/components/ip-main-menu-toggle/ip-main-menu-toggle.d.ts +18 -0
  21. package/dist/types/components/ip-tooltip/ip-tooltip.d.ts +91 -3
  22. package/dist/types/components.d.ts +455 -18
  23. package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/icons.d.ts +12 -0
  24. package/dist/types/home/runner/work/pixel/pixel/.stencil/utils/media-query.d.ts +2 -0
  25. package/dist/types/index.d.ts +9 -0
  26. package/dist/types/services/i18n/i18n.d.ts +90 -0
  27. package/dist/types/services/index.d.ts +3 -0
  28. package/dist/web-components/components/index.js +1 -1
  29. package/dist/web-components/components/ip-button.js +1 -1
  30. package/dist/web-components/components/ip-icon-button.js +1 -1
  31. package/dist/web-components/components/ip-main-menu-group.d.ts +11 -0
  32. package/dist/web-components/components/ip-main-menu-group.js +1 -0
  33. package/dist/web-components/components/ip-main-menu-item.d.ts +11 -0
  34. package/dist/web-components/components/ip-main-menu-item.js +1 -0
  35. package/dist/web-components/components/ip-main-menu-section.d.ts +11 -0
  36. package/dist/web-components/components/ip-main-menu-section.js +1 -0
  37. package/dist/web-components/components/ip-main-menu-toggle.d.ts +11 -0
  38. package/dist/web-components/components/ip-main-menu-toggle.js +1 -0
  39. package/dist/web-components/components/ip-main-menu.d.ts +11 -0
  40. package/dist/web-components/components/ip-main-menu.js +1 -0
  41. package/dist/web-components/components/ip-tooltip.js +1 -1
  42. package/dist/web-components/components/p-BB9-AZXH.js +2 -0
  43. package/dist/web-components/components/p-BVCpLJHm.js +1 -0
  44. package/dist/web-components/components/p-C46ykm0B.js +1 -0
  45. package/dist/web-components/components/p-C5JgSR21.js +1 -0
  46. package/dist/web-components/components/p-Cdum_HLu.js +1 -0
  47. package/dist/web-components/components/p-CfZcYTNP.js +1 -0
  48. package/dist/web-components/components/p-Cjml7mZs.js +1 -0
  49. package/dist/web-components/components/p-D42v9_4Q.js +1 -0
  50. package/dist/web-components/components/p-DHUR9EVo.js +1 -0
  51. package/dist/web-components/components/p-DZvuo-De.js +1 -0
  52. package/dist/web-components/components/p-bEbVkEjw.js +1 -0
  53. package/dist/web-components/components/p-xFc88Xk9.js +1 -0
  54. package/dist/web-components/generated/angular/components.d.ts +168 -7
  55. package/dist/web-components/generated/angular/components.js +291 -12
  56. package/dist/web-components/generated/angular/components.ts +250 -10
  57. package/dist/web-components/generated/angular/index.d.ts +1 -1
  58. package/dist/web-components/generated/angular/index.js +5 -0
  59. package/dist/web-components/generated/angular/index.ts +5 -0
  60. package/dist/web-components/generated/react/components.d.ts +24 -3
  61. package/dist/web-components/generated/react/components.js +51 -2
  62. package/dist/web-components/generated/react/components.ts +73 -5
  63. package/dist/web-components/generated/svelte/components.d.ts +10 -0
  64. package/dist/web-components/generated/vue/components.d.ts +5 -0
  65. package/dist/web-components/generated/vue/components.js +55 -6
  66. package/dist/web-components/generated/vue/components.ts +65 -6
  67. package/llms.txt +32 -0
  68. package/package.json +7 -2
  69. package/dist/web-components/components/ip-icon-button/llm.md +0 -108
  70. package/dist/web-components/components/ip-tooltip/llm.md +0 -151
  71. package/dist/web-components/components/p-BWyvzXuA.js +0 -1
  72. package/dist/web-components/components/p-COraaQeZ.js +0 -1
  73. package/dist/web-components/components/p-Ci0xGmLx.js +0 -1
  74. package/dist/web-components/components/p-D9Ju9vYr.js +0 -1
  75. /package/dist/{migrations → docs/migrations}/v1-to-v2.md +0 -0
  76. /package/dist/{esm → docs}/services/theme-service/llm.md +0 -0
  77. /package/dist/{web-components/components → docs/web-components}/ip-button/llm.md +0 -0
package/LICENSE.md CHANGED
@@ -14,3 +14,14 @@ Norconsult Digital AS.
14
14
 
15
15
  The software is provided "AS IS", without warranties of any kind.
16
16
  Reverse engineering, decompilation, and disassembly are prohibited.
17
+
18
+ ---
19
+
20
+ ## Third-party attribution
21
+
22
+ This package includes SVG icons sourced from Font Awesome Free 7.2.0.
23
+
24
+ - Source: https://fontawesome.com
25
+ - License: https://fontawesome.com/license/free
26
+ - Icons under CC BY 4.0
27
+ - Copyright © Fonticons, Inc.
@@ -0,0 +1,113 @@
1
+ # ip-icon-button
2
+
3
+ A circular icon-only button with a CSS ripple on click and a built-in tooltip on hover. Available in five visual variants shared with `ip-button`, plus two transparent variants (`transparentOnLight`/`transparentOnDark`) for use on surfaces that do not follow the global theme. Requires a `label` attribute for screen reader accessibility — `label` is also used as the tooltip text by default.
4
+
5
+ ## Attributes
6
+
7
+ | Attribute | Type | Default | Allowed values | Description |
8
+ | -------------------- | ------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
9
+ | `variant` | string | `"primary"` | `"primary"` \| `"secondary"` \| `"tertiary"` \| `"brand"` \| `"destructive"` \| `"transparentOnLight"` \| `"transparentOnDark"` | Visual variant of the button. The two transparent variants are interim placeholders used internally by `ip-main-menu` and may change when the dedicated token family lands. |
10
+ | `size` | string | `"medium"` | `"small"` \| `"medium"` \| `"large"` | Controls the size of the button. Affects padding and icon size. |
11
+ | `disabled` | boolean | `false` | — | Disables the button. Also set implicitly when `loading` is `true`. |
12
+ | `loading` | boolean | `false` | — | Replaces the icon with a spinner and disables interaction. Renders a screen-reader-only "Loading..." text. |
13
+ | `type` | string | `"button"` | `"button"` \| `"submit"` \| `"reset"` | Controls form behaviour. Defaults to `"button"` to prevent accidental form submission. |
14
+ | `label` | string | `""` | — | **Required.** Sets `aria-label` for screen readers and is used as the default tooltip text. When empty, the tooltip is implicitly hidden and a development warning is logged. |
15
+ | `disableTooltip` | boolean | `false` | — | Hides the built-in tooltip. Useful when the button is already described by surrounding context. |
16
+ | `tooltipSize` | string | — | `"small"` \| `"medium"` \| `"large"` | Overrides the tooltip size. When unset, the tooltip inherits the button's `size`. |
17
+ | `tooltipPosition` | string | — | `"top"` \| `"right"` \| `"bottom"` \| `"left"` | Position of the tooltip relative to the button. When unset, the tooltip uses its own default (`"top"`). |
18
+ | `tooltipVariant` | string | `"default"` | `"default"` \| `"onLight"` \| `"onDark"` | Color variant of the tooltip. `default` adapts to the active theme. Use `"onLight"`/`"onDark"` when the button sits on a surface whose color does not follow the global theme. |
19
+ | `tooltipHideOnClick` | boolean | `true` | — | When `false`, clicking the button does not dismiss the tooltip. Use for toggle buttons where the tooltip text updates on click (e.g. collapse/expand, pin/unpin). |
20
+ | `aria-expanded` | string | `null` | `"true"` \| `"false"` | Property name: `expanded`. Forwards `aria-expanded` to the inner `<button>` for disclosure patterns (e.g. menu toggles). When `null` (default) the attribute is not rendered. |
21
+
22
+ ## Slots
23
+
24
+ | Slot | Description |
25
+ | --------- | -------------------------------------------------------------------------------------------- |
26
+ | `icon` | The icon element to display. Hidden when `loading` is `true`. Typically an `<i>` or `<svg>`. |
27
+ | `tooltip` | Optional HTML override for the tooltip content. When omitted, the `label` value is used. |
28
+
29
+ ## Size tokens
30
+
31
+ | Size | Padding (all sides) | Icon size |
32
+ | -------- | ----------------------- | ------------------------------------ |
33
+ | `small` | `$ip_spacing_space_100` | `$ip_iconography_size_small` (18px) |
34
+ | `medium` | `$ip_spacing_space_125` | `$ip_iconography_size_medium` (20px) |
35
+ | `large` | `$ip_spacing_space_150` | `$ip_iconography_size_large` (22px) |
36
+
37
+ ## Color tokens
38
+
39
+ | Token | Description |
40
+ | --------------------------------------------------------------------- | ------------------------------------------------------ |
41
+ | `$ip_color_icon_button_background_primary_default` | Primary background, default state |
42
+ | `$ip_color_icon_button_background_primary_hover` | Primary background, hover state |
43
+ | `$ip_color_icon_button_background_primary_active` | Primary background, active state |
44
+ | `$ip_color_button_background_[variant]_default/hover/active/disabled` | Background for secondary, tertiary, brand, destructive |
45
+ | `$ip_color_button_icon_[variant]_default` | Icon color, default state |
46
+ | `$ip_color_button_icon_[variant]_disabled` | Icon color, disabled state |
47
+ | `$ip_color_button_focus_default` | Focus outline color |
48
+
49
+ ## Usage examples
50
+
51
+ ### HTML
52
+
53
+ ```html
54
+ <ip-icon-button label="Save" variant="primary">
55
+ <i slot="icon" class="fas fa-floppy-disk"></i>
56
+ </ip-icon-button>
57
+
58
+ <!-- With HTML tooltip override -->
59
+ <ip-icon-button label="Save" variant="primary">
60
+ <i slot="icon" class="fas fa-floppy-disk"></i>
61
+ <span slot="tooltip">Save <strong>document</strong></span>
62
+ </ip-icon-button>
63
+ ```
64
+
65
+ ### React
66
+
67
+ ```tsx
68
+ import { IpIconButton } from '@norconsult-digital-public/isypixel/web-components/react';
69
+
70
+ <IpIconButton label='Save' variant='primary'>
71
+ <i slot='icon' className='fas fa-floppy-disk' />
72
+ </IpIconButton>;
73
+ ```
74
+
75
+ ### Vue
76
+
77
+ ```html
78
+ <IpIconButton label="Save" variant="primary">
79
+ <i slot="icon" class="fas fa-floppy-disk" />
80
+ </IpIconButton>
81
+ ```
82
+
83
+ ### Angular
84
+
85
+ ```ts
86
+ import { IpIconButton } from '@norconsult-digital-public/isypixel/web-components/angular';
87
+ ```
88
+
89
+ ```html
90
+ <ip-icon-button label="Save" variant="primary">
91
+ <i slot="icon" class="fas fa-floppy-disk"></i>
92
+ </ip-icon-button>
93
+ ```
94
+
95
+ ### Svelte
96
+
97
+ ```html
98
+ <script>
99
+ import '@norconsult-digital-public/isypixel/web-components/ip-icon-button.js';
100
+ </script>
101
+
102
+ <ip-icon-button label="Save" variant="primary">
103
+ <i slot="icon" class="fas fa-floppy-disk"></i>
104
+ </ip-icon-button>
105
+ ```
106
+
107
+ ### Blazor
108
+
109
+ ```html
110
+ <ip-icon-button label="Save" variant="primary">
111
+ <i slot="icon" class="fas fa-floppy-disk"></i>
112
+ </ip-icon-button>
113
+ ```
@@ -0,0 +1,219 @@
1
+ # ip-main-menu
2
+
3
+ Outer sidebar navigation wrapper for ISY applications. Manages three desktop display modes (expanded, auto-hide, collapsed) and a full-height mobile overlay drawer. Must be composed with `ip-main-menu-section`, `ip-main-menu-group`, and `ip-main-menu-item`.
4
+
5
+ > **Opening the drawer on mobile:** The mobile drawer is opened by the separate `ip-main-menu-toggle` component, placed in your top bar. The two communicate through a shared store — no wiring needed. See `ip-main-menu-toggle/llm.md`.
6
+
7
+ > **Layout requirement:** On desktop, the parent element must use `display: flex` or `display: grid` with a defined height, otherwise the sidebar will not fill the viewport. Example: `<div style="display:flex; height:100vh;"><ip-main-menu>...</ip-main-menu><main>...</main></div>`. At the mobile breakpoint the nav becomes a fixed overlay drawer and the host collapses to take no space in the layout.
8
+
9
+ > **Breakpoint:** Mobile drawer behaviour activates at or below the `mobileBreakpoint` prop (default `1024px`). The value is shared through the store so `ip-main-menu-toggle` switches at the exact same width with no extra wiring. Below 768px the drawer spans the full viewport width (a fixed phone-size breakpoint, not configurable). No breakpoint design token is available yet; these values are hardcoded.
10
+
11
+ > **Single-instance:** Use one `<ip-main-menu>` per page. The desktop mode and mobile drawer state are kept in a module-level store, so multiple instances on the same page will share state and stay in sync — there is no per-instance isolation.
12
+
13
+ ## Attributes
14
+
15
+ | Attribute | Type | Default | Allowed values | Description |
16
+ | ------------------ | ------------------------------------------ | ------------ | ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
17
+ | `heading` | `string` | — | Any string | Required. App name shown in expanded mode. Used as `aria-label` on `<nav>` and as `aria-label` on the brand element. |
18
+ | `mode` | `'expanded' \| 'auto-hide' \| 'collapsed'` | `'expanded'` | `'expanded'`, `'auto-hide'`, `'collapsed'` | Desktop display mode. Sets initial state; internal state tracks user interactions. Not persisted across refreshes or browser sessions — persist via `ipModeChange` (see below). |
19
+ | `brandHref` | `string` | — | Any URL string | Optional. When set, the brand area (logo + heading) renders as an `<a>` linking to this URL. Without it, it renders as a `<button>` that emits `ipBrandClick`. |
20
+ | `expandDelay` | `number` | `300` | Any non-negative number (ms) | Hover-intent delay before `auto-hide` expands. Increase to ignore longer drift-overs, decrease for snappier expansion. Only applies in `auto-hide` mode. |
21
+ | `collapseDelay` | `number` | `300` | Any non-negative number (ms) | Grace period before `auto-hide` collapses after the mouse leaves. Increase to forgive accidental cursor slips, decrease for snappier collapse. Only applies in `auto-hide` mode. |
22
+ | `mobileBreakpoint` | `string` | `'1024px'` | Any CSS length (e.g. `1024px`, `64rem`) | Viewport width at or below which the menu becomes a mobile drawer and `ip-main-menu-toggle` appears. Shared through the store so both components switch at the same width. |
23
+
24
+ ### Desktop modes
25
+
26
+ | Mode | Width | Behaviour |
27
+ | ----------- | ----- | ----------------------------------------- |
28
+ | `expanded` | 230px | Full labels and icons visible. |
29
+ | `auto-hide` | 64px | Icons only. Expands temporarily on hover. |
30
+ | `collapsed` | 64px | Icons only. No hover expansion. |
31
+
32
+ Mode transitions:
33
+
34
+ - **expanded → auto-hide**: click pin button
35
+ - **expanded → collapsed**: click collapse button
36
+ - **collapsed → expanded**: click collapse button (rotated 180°)
37
+ - **auto-hide → expanded**: click pin/unpin button
38
+
39
+ > The collapse button is only shown in `expanded` and `collapsed` modes. The pin button is only shown in `expanded` and `auto-hide` modes.
40
+
41
+ ## Slots
42
+
43
+ | Slot | Description |
44
+ | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
45
+ | `logo` | Custom logo shown in collapsed/auto-hide mode. Falls back to the built-in ISY logo if omitted. |
46
+ | `default` | Main navigation content (`ip-main-menu-section`, `ip-main-menu-group`, `ip-main-menu-item`). |
47
+ | `bottom` | Content pinned to the bottom of the sidebar (e.g. user profile, logout). |
48
+ | `icon-close` | Mobile drawer close icon. Default: Font Awesome Free `xmark` (solid). Replace by slotting your own. |
49
+ | `icon-pin` | Desktop pin button icon — shown when mode is `expanded`. Default: Font Awesome Free `thumbtack` (solid). Replace by slotting your own. |
50
+ | `icon-unpin` | Desktop pin button icon — shown when mode is `auto-hide`. Default: same `thumbtack` SVG as `icon-pin`, rotated 45° via CSS — identical size, no clipping. The intended design icon is FA Pro `thumbtack-angle` (sharp regular); inject it through this slot when a Pro license is available (slotted icons are not auto-rotated). |
51
+ | `icon-collapse` | Desktop collapse/expand button icon. Rotates 180° based on mode. Default: Font Awesome Free `chevron-left` (solid). Replace by slotting your own. |
52
+
53
+ > **Icon fallbacks:** Default SVGs are inlined from Font Awesome Free 7.2.0 (CC BY 4.0 — see LICENSE.md). Each fallback is a separate export in `icons.ts`, so any default a consumer overrides via the matching `icon-*` slot is tree-shaken from the bundle.
54
+
55
+ ## Injecting icons
56
+
57
+ ISY applications use Font Awesome per the design system, and the bundled fallbacks are already FA Free SVGs. Slot injection is therefore only needed in two cases:
58
+
59
+ **1. The unpin icon (recommended when an FA Pro license is available).** The intended design icon for `icon-unpin` is [`thumbtack-angle`](https://fontawesome.com/icons/sharp/regular/thumbtack-angle) (sharp regular), which is FA Pro and cannot be bundled for license reasons. The built-in fallback approximates it with the Free `thumbtack` rotated 45°. Inject the intended icon when the consuming application has a Pro license:
60
+
61
+ ```html
62
+ <ip-main-menu heading="My Application" brand-href="/">
63
+ <i slot="icon-unpin" class="fa-sharp fa-regular fa-thumbtack-angle"></i>
64
+ </ip-main-menu>
65
+ ```
66
+
67
+ **2. A different icon library.** If the application does not use Font Awesome, replace all four control icons:
68
+
69
+ ```html
70
+ <ip-main-menu heading="My Application" brand-href="/">
71
+ <span slot="icon-close">...</span>
72
+ <span slot="icon-pin">...</span>
73
+ <span slot="icon-unpin">...</span>
74
+ <span slot="icon-collapse">...</span>
75
+ </ip-main-menu>
76
+ ```
77
+
78
+ The same pattern applies in all frameworks: slot the element into the matching named slot.
79
+
80
+ ## Events
81
+
82
+ | Event | Payload | Description |
83
+ | -------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
84
+ | `ipModeChange` | `CustomEvent<'expanded' \| 'auto-hide' \| 'collapsed'>` | Fires when the user changes desktop mode. |
85
+ | `ipMobileOpenChange` | `CustomEvent<boolean>` | Fires when the mobile drawer opens or closes. Use this to lock body scroll. |
86
+ | `ipBrandClick` | `CustomEvent<void>` | Fires when the brand area is clicked and `brandHref` is not set. Use for SPA client-side navigation. |
87
+
88
+ ### Persisting mode across sessions
89
+
90
+ The mode lives in memory only; refreshing the page resets it to the `mode` prop. Persist it yourself until a dedicated menu state persistence service is added to Pixel:
91
+
92
+ ```javascript
93
+ const nav = document.querySelector('ip-main-menu');
94
+ nav.mode = localStorage.getItem('nav-mode') ?? 'expanded';
95
+ nav.addEventListener('ipModeChange', (e) => {
96
+ localStorage.setItem('nav-mode', e.detail);
97
+ });
98
+ ```
99
+
100
+ ## Design tokens
101
+
102
+ | Token | Role |
103
+ | ----------------------------------------------- | ----------------------------------------------------------------------------------- |
104
+ | `ip_color_menu_main_background_primary_default` | Sidebar background |
105
+ | `ip_color_button_focus_default` | Focus outline on control buttons (interim until a menu-specific focus token exists) |
106
+
107
+ > **Token gaps (flagged to design team):**
108
+ >
109
+ > - Text/icon colour tokens for sidebar controls (`ip_color_menu_main_*_text`), heading, and logo
110
+ > - Control button hover background and scrollbar colours (hardcoded with `//TODO:` comments)
111
+ > - Width tokens (230px expanded, 64px collapsed)
112
+ > - Mobile breakpoint token (drawer breakpoint defaults to 1024px via `mobileBreakpoint`; full-width phone breakpoint hardcoded to 768px)
113
+ > - Mobile backdrop overlay colour token
114
+
115
+ ## Usage examples
116
+
117
+ ### HTML
118
+
119
+ ```html
120
+ <!-- With brandHref — brand area renders as <a> -->
121
+ <div style="display:flex; height:100vh;">
122
+ <ip-main-menu heading="My Application" brand-href="/">
123
+ <ip-main-menu-section label="Main">
124
+ <ip-main-menu-item label="Dashboard" active>
125
+ <svg slot="icon" ...></svg>
126
+ </ip-main-menu-item>
127
+ </ip-main-menu-section>
128
+ <ip-main-menu-item label="Settings" slot="bottom">
129
+ <svg slot="icon" ...></svg>
130
+ </ip-main-menu-item>
131
+ </ip-main-menu>
132
+ <main>...</main>
133
+ </div>
134
+
135
+ <!-- Without brandHref — brand area renders as <button>, handle ipBrandClick for SPA navigation -->
136
+ <ip-main-menu heading="My Application" id="nav"></ip-main-menu>
137
+ <script>
138
+ document.getElementById('nav').addEventListener('ipBrandClick', () => router.navigate('/'));
139
+ </script>
140
+ ```
141
+
142
+ ### React
143
+
144
+ ```tsx
145
+ import { IpMainMenu, IpMainMenuSection, IpMainMenuItem } from '@norconsult-digital-public/isypixel/web-components/react';
146
+
147
+ // href-based navigation
148
+ <IpMainMenu heading='My Application' brandHref='/'>
149
+ <IpMainMenuSection label='Main'>
150
+ <IpMainMenuItem label='Dashboard' active />
151
+ </IpMainMenuSection>
152
+ </IpMainMenu>
153
+
154
+ // SPA / client-side navigation
155
+ <IpMainMenu heading='My Application' onIpBrandClick={() => navigate('/')}>
156
+ ...
157
+ </IpMainMenu>
158
+ ```
159
+
160
+ ### Vue
161
+
162
+ ```vue
163
+ <!-- href-based -->
164
+ <IpMainMenu heading="My Application" brand-href="/">
165
+ <IpMainMenuSection label="Main">
166
+ <IpMainMenuItem label="Dashboard" :active="true" />
167
+ </IpMainMenuSection>
168
+ </IpMainMenu>
169
+
170
+ <!-- SPA -->
171
+ <IpMainMenu heading="My Application" @ip-brand-click="router.push('/')">
172
+ ...
173
+ </IpMainMenu>
174
+ ```
175
+
176
+ ### Angular
177
+
178
+ ```html
179
+ <!-- href-based -->
180
+ <ip-main-menu heading="My Application" brandHref="/">
181
+ <ip-main-menu-section label="Main">
182
+ <ip-main-menu-item label="Dashboard" [active]="true"></ip-main-menu-item>
183
+ </ip-main-menu-section>
184
+ </ip-main-menu>
185
+
186
+ <!-- SPA -->
187
+ <ip-main-menu heading="My Application" (ipBrandClick)="router.navigate(['/'])"> </ip-main-menu>
188
+ ```
189
+
190
+ ### Svelte
191
+
192
+ ```svelte
193
+ <!-- href-based -->
194
+ <IpMainMenu heading="My Application" brandHref="/">
195
+ <IpMainMenuSection label="Main">
196
+ <IpMainMenuItem label="Dashboard" active />
197
+ </IpMainMenuSection>
198
+ </IpMainMenu>
199
+
200
+ <!-- SPA -->
201
+ <IpMainMenu heading="My Application" on:ipBrandClick={() => goto('/')}>
202
+ ...
203
+ </IpMainMenu>
204
+ ```
205
+
206
+ ### Blazor
207
+
208
+ ```razor
209
+ <!-- href-based -->
210
+ <ip-main-menu heading="My Application" brand-href="/">
211
+ <ip-main-menu-section label="Main">
212
+ <ip-main-menu-item label="Dashboard" active="true"></ip-main-menu-item>
213
+ </ip-main-menu-section>
214
+ </ip-main-menu>
215
+
216
+ <!-- SPA -->
217
+ <ip-main-menu heading="My Application" @onipBrandClick="NavigateHome">
218
+ </ip-main-menu>
219
+ ```
@@ -0,0 +1,114 @@
1
+ # ip-main-menu-group
2
+
3
+ Collapsible group of navigation items with a label, optional icon, and an animated chevron. The chevron rotates 180° on open/close. In collapsed mode the label and chevron are hidden; a tooltip appears on hover/focus.
4
+
5
+ > **Note:** This component must be used inside an `ip-main-menu`.
6
+
7
+ ## Attributes
8
+
9
+ | Attribute | Type | Default | Allowed values | Description |
10
+ | --------- | --------- | ------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
11
+ | `label` | `string` | — | Any string | Required. Group label in expanded mode. Used as accessible name and tooltip in collapsed mode. |
12
+ | `active` | `boolean` | `false` | `true`, `false` | Whether any child item is active. Applies selected styling to the group trigger. |
13
+ | `open` | `boolean` | `false` | `true`, `false` | Initial expanded state. Internal state takes over after first interaction (uncontrolled pattern). Not persisted across refreshes or browser sessions — listen to `ipOpenChange` to persist. A menu state persistence service may be added to Pixel later. |
14
+
15
+ ## Slots
16
+
17
+ | Slot | Description |
18
+ | -------------- | ------------------------------------------------------------------------------------- |
19
+ | `default` | `ip-main-menu-item` children. |
20
+ | `icon` | Icon displayed to the left of the label. |
21
+ | `icon-chevron` | Chevron icon. Default: inline SVG arrow. Rotates 180° via CSS transition when `open`. |
22
+
23
+ > **Custom chevron:** Slot `icon-chevron` to replace the built-in arrow, e.g. `<i slot="icon-chevron" class="fa-solid fa-chevron-down"></i>`. The slotted icon rotates 180° on open/close just like the default.
24
+
25
+ ## Events
26
+
27
+ | Event | Payload | Description |
28
+ | -------------- | ---------------------- | ----------------------------------------------------- |
29
+ | `ipOpenChange` | `CustomEvent<boolean>` | Fires when the user toggles the group open or closed. |
30
+
31
+ ## Design tokens
32
+
33
+ | Token | Role |
34
+ | ------------------------------------------------------------------- | ----------------------------------------------------------------------- |
35
+ | `ip_color_menu_main_item_background_primary_default` | Group trigger background (default) |
36
+ | `ip_color_menu_main_group_item_background_primary_default` | Group trigger background (open) and child item background |
37
+ | `ip_color_menu_main_group_item_background_primary_hover` | Group trigger background (hover) |
38
+ | `ip_color_menu_main_group_item_background_primary_active` | Group trigger background (pressed) |
39
+ | `ip_color_menu_main_group_item_background_primary_selected_default` | Group trigger background when `active` |
40
+ | `ip_color_menu_main_group_item_background_primary_selected_hover` | Active group trigger background (hover) |
41
+ | `ip_color_menu_main_group_item_background_primary_selected_active` | Active group trigger background (pressed) |
42
+ | `ip_color_menu_main_item_vertical_divider_primary_default` | Left-border accent on active group trigger |
43
+ | `ip_color_button_focus_default` | Focus outline colour (interim until a menu-specific focus token exists) |
44
+
45
+ > **Token gaps:** Text/icon colour tokens for group items are not yet available. Hardcoded values are used with `// TODO` comments.
46
+
47
+ ## Usage examples
48
+
49
+ ### HTML
50
+
51
+ ```html
52
+ <ip-main-menu heading="My App">
53
+ <ip-main-menu-group label="Reports">
54
+ <svg slot="icon" ...></svg>
55
+ <ip-main-menu-item label="Monthly"></ip-main-menu-item>
56
+ <ip-main-menu-item label="Yearly"></ip-main-menu-item>
57
+ </ip-main-menu-group>
58
+ </ip-main-menu>
59
+ ```
60
+
61
+ ### React
62
+
63
+ ```tsx
64
+ <IpMainMenu heading='My App'>
65
+ <IpMainMenuGroup label='Reports' onIpOpenChange={(e) => console.log(e.detail)}>
66
+ <svg slot='icon' />
67
+ <IpMainMenuItem label='Monthly' />
68
+ </IpMainMenuGroup>
69
+ </IpMainMenu>
70
+ ```
71
+
72
+ ### Vue
73
+
74
+ ```vue
75
+ <IpMainMenu heading="My App">
76
+ <IpMainMenuGroup label="Reports" @ip-open-change="handleChange">
77
+ <svg slot="icon" />
78
+ <IpMainMenuItem label="Monthly" />
79
+ </IpMainMenuGroup>
80
+ </IpMainMenu>
81
+ ```
82
+
83
+ ### Angular
84
+
85
+ ```html
86
+ <ip-main-menu heading="My App">
87
+ <ip-main-menu-group label="Reports" (ipOpenChange)="handleChange($event)">
88
+ <svg slot="icon"></svg>
89
+ <ip-main-menu-item label="Monthly"></ip-main-menu-item>
90
+ </ip-main-menu-group>
91
+ </ip-main-menu>
92
+ ```
93
+
94
+ ### Svelte
95
+
96
+ ```svelte
97
+ <IpMainMenu heading="My App">
98
+ <IpMainMenuGroup label="Reports" on:ipOpenChange={handleChange}>
99
+ <svg slot="icon" />
100
+ <IpMainMenuItem label="Monthly" />
101
+ </IpMainMenuGroup>
102
+ </IpMainMenu>
103
+ ```
104
+
105
+ ### Blazor
106
+
107
+ ```razor
108
+ <ip-main-menu heading="My App">
109
+ <ip-main-menu-group label="Reports">
110
+ <svg slot="icon"></svg>
111
+ <ip-main-menu-item label="Monthly"></ip-main-menu-item>
112
+ </ip-main-menu-group>
113
+ </ip-main-menu>
114
+ ```
@@ -0,0 +1,104 @@
1
+ # ip-main-menu-item
2
+
3
+ Individual navigation item for use inside `ip-main-menu`. Renders as an `<a>` when `href` is provided, otherwise as a `<button>`. In collapsed mode the label is hidden and a tooltip appears on hover/focus.
4
+
5
+ > **Note:** This component must be used inside an `ip-main-menu` to receive the CSS custom properties that control collapsed/auto-hide behaviour.
6
+
7
+ > **Mobile drawer:** Clicking an item automatically closes the `ip-main-menu` mobile drawer through the shared store, so navigation in drawer mode needs no extra wiring.
8
+
9
+ ## Attributes
10
+
11
+ | Attribute | Type | Default | Allowed values | Description |
12
+ | ---------- | --------------------- | ----------- | ----------------------- | -------------------------------------------------------------------------------------- |
13
+ | `label` | `string` | — | Any string | Required. Item text in expanded mode. Used as accessible name and tooltip text. |
14
+ | `active` | `boolean` | `false` | `true`, `false` | Marks this item as the current page. Sets `aria-current="page"` automatically. |
15
+ | `href` | `string \| undefined` | `undefined` | Any URL string | If set, renders as `<a>`. Otherwise renders as `<button>`. |
16
+ | `target` | `string \| undefined` | `undefined` | `_blank`, `_self`, etc. | Forwarded to `<a target>`. Only relevant when `href` is set. |
17
+ | `disabled` | `boolean` | `false` | `true`, `false` | Disables interaction. On `<a>` uses `aria-disabled` + `tabindex="-1"` + blocked click. |
18
+
19
+ ## Slots
20
+
21
+ | Slot | Description |
22
+ | ------ | ---------------------------------------- |
23
+ | `icon` | Icon displayed to the left of the label. |
24
+
25
+ ## Design tokens
26
+
27
+ | Token | Role |
28
+ | ------------------------------------------------------------- | ------------------------------------------------ |
29
+ | `ip_color_menu_main_item_background_primary_default` | Item background (default) |
30
+ | `ip_color_menu_main_item_background_primary_hover` | Item background (hover) |
31
+ | `ip_color_menu_main_item_background_primary_active` | Item background (pressed) |
32
+ | `ip_color_menu_main_item_background_primary_selected_default` | Item background (active/selected) |
33
+ | `ip_color_menu_main_item_background_primary_selected_hover` | Selected item background (hover) |
34
+ | `ip_color_menu_main_item_background_primary_selected_active` | Selected item background (pressed) |
35
+ | `ip_color_menu_main_item_vertical_divider_primary_default` | Left-border accent on active item; focus outline |
36
+
37
+ > **Token gaps:** Text/icon colour tokens for `menu_main` items are not yet available. Hardcoded values are used with `// TODO` comments.
38
+
39
+ ## Usage examples
40
+
41
+ ### HTML
42
+
43
+ ```html
44
+ <ip-main-menu heading="My App">
45
+ <ip-main-menu-item label="Dashboard" active>
46
+ <svg slot="icon" ...></svg>
47
+ </ip-main-menu-item>
48
+ <ip-main-menu-item label="Settings" href="/settings">
49
+ <svg slot="icon" ...></svg>
50
+ </ip-main-menu-item>
51
+ </ip-main-menu>
52
+ ```
53
+
54
+ ### React
55
+
56
+ ```tsx
57
+ import { IpMainMenu, IpMainMenuItem } from '@norconsult-digital-public/isypixel/web-components/react';
58
+
59
+ <IpMainMenu heading='My App'>
60
+ <IpMainMenuItem label='Dashboard' active>
61
+ <svg slot='icon' />
62
+ </IpMainMenuItem>
63
+ </IpMainMenu>;
64
+ ```
65
+
66
+ ### Vue
67
+
68
+ ```vue
69
+ <IpMainMenu heading="My App">
70
+ <IpMainMenuItem label="Dashboard" :active="true">
71
+ <svg slot="icon" />
72
+ </IpMainMenuItem>
73
+ </IpMainMenu>
74
+ ```
75
+
76
+ ### Angular
77
+
78
+ ```html
79
+ <ip-main-menu heading="My App">
80
+ <ip-main-menu-item label="Dashboard" [active]="true">
81
+ <svg slot="icon"></svg>
82
+ </ip-main-menu-item>
83
+ </ip-main-menu>
84
+ ```
85
+
86
+ ### Svelte
87
+
88
+ ```svelte
89
+ <IpMainMenu heading="My App">
90
+ <IpMainMenuItem label="Dashboard" active>
91
+ <svg slot="icon" />
92
+ </IpMainMenuItem>
93
+ </IpMainMenu>
94
+ ```
95
+
96
+ ### Blazor
97
+
98
+ ```razor
99
+ <ip-main-menu heading="My App">
100
+ <ip-main-menu-item label="Dashboard" active="true">
101
+ <svg slot="icon"></svg>
102
+ </ip-main-menu-item>
103
+ </ip-main-menu>
104
+ ```