@allxsmith/bestax-bulma 5.60.0 → 5.62.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.
Files changed (98) hide show
  1. package/dist/bestax.css +1 -1
  2. package/dist/bestax.css.map +1 -1
  3. package/dist/esm/components/Carousel.js +3 -43
  4. package/dist/esm/components/Carousel.js.map +1 -1
  5. package/dist/esm/components/Command.js +3 -3
  6. package/dist/esm/components/Navbar.js +3 -1
  7. package/dist/esm/components/Navbar.js.map +1 -1
  8. package/dist/esm/components/Popover.js +7 -27
  9. package/dist/esm/components/Popover.js.map +1 -1
  10. package/dist/esm/components/Sidebar.js +17 -58
  11. package/dist/esm/components/Sidebar.js.map +1 -1
  12. package/dist/esm/components/TreeView.js +14 -10
  13. package/dist/esm/components/TreeView.js.map +1 -1
  14. package/dist/esm/form/ColorPicker.js +4 -4
  15. package/dist/esm/form/ColorPicker.js.map +1 -1
  16. package/dist/esm/form/Combobox.js +11 -16
  17. package/dist/esm/form/Combobox.js.map +1 -1
  18. package/dist/esm/form/Field.js.map +1 -1
  19. package/dist/esm/form/TreeSelect.js +395 -0
  20. package/dist/esm/form/TreeSelect.js.map +1 -0
  21. package/dist/esm/form/_pickerInternals/PickerPopover.js +5 -1
  22. package/dist/esm/form/_pickerInternals/PickerPopover.js.map +1 -1
  23. package/dist/esm/form/_selectInternals/DialogSelect.js +208 -0
  24. package/dist/esm/form/_selectInternals/DialogSelect.js.map +1 -0
  25. package/dist/esm/form/_selectInternals/ValueTags.js +28 -0
  26. package/dist/esm/form/_selectInternals/ValueTags.js.map +1 -0
  27. package/dist/esm/helpers/overlayStack.js +33 -1
  28. package/dist/esm/helpers/overlayStack.js.map +1 -1
  29. package/dist/esm/helpers/treeData.js +97 -0
  30. package/dist/esm/helpers/treeData.js.map +1 -0
  31. package/dist/esm/helpers/useBulmaViewport.js +82 -0
  32. package/dist/esm/helpers/useBulmaViewport.js.map +1 -0
  33. package/dist/esm/helpers/useComboboxEngine.js +2 -2
  34. package/dist/esm/helpers/useComboboxEngine.js.map +1 -1
  35. package/dist/esm/helpers/useControlled.js +30 -0
  36. package/dist/esm/helpers/useControlled.js.map +1 -0
  37. package/dist/esm/helpers/useInertSiblings.js +7 -3
  38. package/dist/esm/helpers/useInertSiblings.js.map +1 -1
  39. package/dist/esm/helpers/useOutsidePress.js +53 -0
  40. package/dist/esm/helpers/useOutsidePress.js.map +1 -0
  41. package/dist/esm/helpers/useOverlayFocus.js +74 -0
  42. package/dist/esm/helpers/useOverlayFocus.js.map +1 -0
  43. package/dist/esm/helpers/useTreeView.js +15 -13
  44. package/dist/esm/helpers/useTreeView.js.map +1 -1
  45. package/dist/esm/layout/AppFrame.js +438 -0
  46. package/dist/esm/layout/AppFrame.js.map +1 -0
  47. package/dist/extras.css +1 -1
  48. package/dist/extras.css.map +1 -1
  49. package/dist/index.cjs +1767 -518
  50. package/dist/index.cjs.map +1 -1
  51. package/dist/index.esm.js +2 -0
  52. package/dist/index.esm.js.map +1 -1
  53. package/dist/types/components/Navbar.d.ts +4 -3
  54. package/dist/types/form/Field.d.ts +1 -1
  55. package/dist/types/form/TreeSelect.d.ts +308 -0
  56. package/dist/types/form/_pickerInternals/PickerPopover.d.ts +8 -0
  57. package/dist/types/form/_selectInternals/DialogSelect.d.ts +86 -0
  58. package/dist/types/form/_selectInternals/ValueTags.d.ts +40 -0
  59. package/dist/types/helpers/overlayStack.d.ts +17 -0
  60. package/dist/types/helpers/treeData.d.ts +48 -0
  61. package/dist/types/helpers/useBulmaViewport.d.ts +34 -0
  62. package/dist/types/helpers/useControlled.d.ts +14 -0
  63. package/dist/types/helpers/useInertSiblings.d.ts +4 -1
  64. package/dist/types/helpers/useOutsidePress.d.ts +24 -0
  65. package/dist/types/helpers/useOverlayFocus.d.ts +44 -0
  66. package/dist/types/helpers/useTreeView.d.ts +30 -0
  67. package/dist/types/index.d.ts +2 -0
  68. package/dist/types/layout/AppFrame.d.ts +306 -0
  69. package/dist/types-cjs/components/Navbar.d.ts +4 -3
  70. package/dist/types-cjs/form/Field.d.ts +1 -1
  71. package/dist/types-cjs/form/TreeSelect.d.ts +308 -0
  72. package/dist/types-cjs/form/_pickerInternals/PickerPopover.d.ts +8 -0
  73. package/dist/types-cjs/form/_selectInternals/DialogSelect.d.ts +86 -0
  74. package/dist/types-cjs/form/_selectInternals/ValueTags.d.ts +40 -0
  75. package/dist/types-cjs/helpers/overlayStack.d.ts +17 -0
  76. package/dist/types-cjs/helpers/treeData.d.ts +48 -0
  77. package/dist/types-cjs/helpers/useBulmaViewport.d.ts +34 -0
  78. package/dist/types-cjs/helpers/useControlled.d.ts +14 -0
  79. package/dist/types-cjs/helpers/useInertSiblings.d.ts +4 -1
  80. package/dist/types-cjs/helpers/useOutsidePress.d.ts +24 -0
  81. package/dist/types-cjs/helpers/useOverlayFocus.d.ts +44 -0
  82. package/dist/types-cjs/helpers/useTreeView.d.ts +30 -0
  83. package/dist/types-cjs/index.d.ts +2 -0
  84. package/dist/types-cjs/layout/AppFrame.d.ts +306 -0
  85. package/dist/versions/bestax-no-dark-mode.css +1 -1
  86. package/dist/versions/bestax-no-dark-mode.css.map +1 -1
  87. package/dist/versions/bestax-no-helpers-prefixed.css +1 -1
  88. package/dist/versions/bestax-no-helpers-prefixed.css.map +1 -1
  89. package/dist/versions/bestax-no-helpers.css +1 -1
  90. package/dist/versions/bestax-no-helpers.css.map +1 -1
  91. package/dist/versions/bestax-prefixed.css +1 -1
  92. package/dist/versions/bestax-prefixed.css.map +1 -1
  93. package/package.json +1 -1
  94. package/src/scss/form/_index.scss +1 -0
  95. package/src/scss/form/_picker-popover.scss +6 -0
  96. package/src/scss/form/_treeselect.scss +146 -0
  97. package/src/scss/layout/_appframe.scss +306 -0
  98. package/src/scss/layout/_index.scss +1 -0
@@ -62,6 +62,12 @@ $picker-trigger-hover-color: cv.getVar('text-strong') !default;
62
62
  right: 0;
63
63
  margin-bottom: cv.getVar('picker-popover-offset');
64
64
  }
65
+ // At least as wide as the anchor it's placed against, as a list under a
66
+ // field is. Portaled, the anchor's width comes inline instead, since 100%
67
+ // there would be the viewport's.
68
+ &.#{iv.$class-prefix}has-anchor-width:not(.#{iv.$class-prefix}is-portal) {
69
+ min-width: 100%;
70
+ }
65
71
  // Portaled: fixed to the viewport at the top and left the positioning hook
66
72
  // sets inline, so the corner's own right and bottom must not apply. Left
67
73
  // in, `right: 0` stretches the panel to the viewport's right edge and the
@@ -0,0 +1,146 @@
1
+ // Bestax Extras - TreeSelect Styles
2
+ // A form field whose options are a tree. The field is Bulma's input, the
3
+ // panel the pickers' popover (`--bulma-picker-popover-*`) and the tree
4
+ // TreeView's (`--bulma-tree-view-*`), so this draws what sits between them:
5
+ // the chevron and the clear button on the field, the panel's height, the
6
+ // search box over the tree and the message when a search finds nothing. The
7
+ // panel is at least as wide as the field through the picker popover's own
8
+ // `has-anchor-width` rule.
9
+
10
+ @use 'bulma/sass/utilities/initial-variables' as iv;
11
+ @use 'bulma/sass/utilities/css-variables' as cv;
12
+
13
+ // The tree scrolls past this, as Combobox's list does.
14
+ $tree-select-panel-max-height: 15rem !default;
15
+ $tree-select-search-gap: 0.5rem !default;
16
+ // The chevron's box at the field's inline end, drawn as a Control's icon is.
17
+ // Bulma registers its input variables on the field and its Control, which the
18
+ // root is outside, so these start from the tokens those start from.
19
+ $tree-select-chevron-width: cv.getVar('control-height') !default;
20
+ $tree-select-chevron-color: cv.getVar('text-light') !default;
21
+ $tree-select-chevron-hover-color: cv.getVar('text-weak') !default;
22
+ $tree-select-chevron-focus-color: cv.getVar('link') !default;
23
+ // Over the field, as Bulma stacks a Control's icon, and the clear button
24
+ // over the chevron.
25
+ $tree-select-chevron-z-index: 4 !default;
26
+ $tree-select-clear-z-index: 5 !default;
27
+ $tree-select-empty-color: cv.getVar('text-weak') !default;
28
+ $tree-select-empty-padding: 0.5em 0.75em !default;
29
+ // Room around the tree for the focus ring of a row at its edge, which the
30
+ // scrolling would cut off: the ring's width and its offset.
31
+ $tree-select-tree-inset: 4px !default;
32
+
33
+ // Registered on the root, which a panel in place sits inside and inherits
34
+ // from, so a value set on the root or through `className` reaches it, and on
35
+ // a portaled panel, which a portal puts outside the root, so it carries its
36
+ // own copy, as Combobox's menu does.
37
+ .#{iv.$class-prefix}tree-select,
38
+ .#{iv.$class-prefix}tree-select-panel.#{iv.$class-prefix}is-portal {
39
+ @include cv.register-vars(
40
+ (
41
+ 'tree-select-panel-max-height': #{$tree-select-panel-max-height},
42
+ 'tree-select-search-gap': #{$tree-select-search-gap},
43
+ 'tree-select-chevron-width': #{$tree-select-chevron-width},
44
+ 'tree-select-chevron-color': #{$tree-select-chevron-color},
45
+ 'tree-select-chevron-hover-color': #{$tree-select-chevron-hover-color},
46
+ 'tree-select-chevron-focus-color': #{$tree-select-chevron-focus-color},
47
+ 'tree-select-chevron-z-index': #{$tree-select-chevron-z-index},
48
+ 'tree-select-clear-z-index': #{$tree-select-clear-z-index},
49
+ 'tree-select-empty-color': #{$tree-select-empty-color},
50
+ 'tree-select-empty-padding': #{$tree-select-empty-padding},
51
+ 'tree-select-tree-inset': #{$tree-select-tree-inset},
52
+ )
53
+ );
54
+ }
55
+
56
+ // What the panel in place, the chevron and the clear button are placed
57
+ // against, when a Control around it holds no other field.
58
+ .#{iv.$class-prefix}tree-select {
59
+ position: relative;
60
+
61
+ .#{iv.$class-prefix}input {
62
+ cursor: pointer;
63
+ padding-inline-end: cv.getVar('tree-select-chevron-width');
64
+ }
65
+
66
+ &.#{iv.$class-prefix}has-clear .#{iv.$class-prefix}input {
67
+ padding-inline-end: calc(2 * #{cv.getVar('tree-select-chevron-width')});
68
+ }
69
+
70
+ .#{iv.$class-prefix}input[disabled] {
71
+ cursor: not-allowed;
72
+ }
73
+ }
74
+
75
+ // Bulma's Control icon, at the inline end, where a press goes to the field.
76
+ .#{iv.$class-prefix}tree-select-chevron {
77
+ align-items: center;
78
+ color: cv.getVar('tree-select-chevron-color');
79
+ display: flex;
80
+ height: 100%;
81
+ inset-block-start: 0;
82
+ inset-inline-end: 0;
83
+ justify-content: center;
84
+ pointer-events: none;
85
+ position: absolute;
86
+ width: cv.getVar('tree-select-chevron-width');
87
+ z-index: cv.getVar('tree-select-chevron-z-index');
88
+ }
89
+
90
+ .#{iv.$class-prefix}tree-select .#{iv.$class-prefix}input {
91
+ &:hover ~ .#{iv.$class-prefix}tree-select-chevron {
92
+ color: cv.getVar('tree-select-chevron-hover-color');
93
+ }
94
+
95
+ &:focus ~ .#{iv.$class-prefix}tree-select-chevron,
96
+ &.#{iv.$class-prefix}is-focused ~ .#{iv.$class-prefix}tree-select-chevron,
97
+ &[aria-expanded='true'] ~ .#{iv.$class-prefix}tree-select-chevron {
98
+ color: cv.getVar('tree-select-chevron-focus-color');
99
+ }
100
+
101
+ &[disabled] ~ .#{iv.$class-prefix}tree-select-chevron {
102
+ color: cv.getVar('input-disabled-color');
103
+ }
104
+
105
+ // The chevron's box is in em, so it follows the field's size.
106
+ &.#{iv.$class-prefix}is-small ~ * {
107
+ font-size: cv.getVar('size-small');
108
+ }
109
+
110
+ &.#{iv.$class-prefix}is-medium ~ * {
111
+ font-size: cv.getVar('size-medium');
112
+ }
113
+
114
+ &.#{iv.$class-prefix}is-large ~ * {
115
+ font-size: cv.getVar('size-large');
116
+ }
117
+ }
118
+
119
+ // Beside the chevron, centred on the field's height.
120
+ .#{iv.$class-prefix}tree-select-clear {
121
+ inset-block-start: 50%;
122
+ inset-inline-end: cv.getVar('tree-select-chevron-width');
123
+ position: absolute;
124
+ transform: translateY(-50%);
125
+ z-index: cv.getVar('tree-select-clear-z-index');
126
+ }
127
+
128
+ .#{iv.$class-prefix}tree-select-panel {
129
+ display: flex;
130
+ flex-direction: column;
131
+ gap: cv.getVar('tree-select-search-gap');
132
+
133
+ // The tree scrolls, with room for the focus ring of the row at its edge,
134
+ // and still lines up with the search box over it.
135
+ > .#{iv.$class-prefix}tree-view {
136
+ margin-inline: calc(-1 * #{cv.getVar('tree-select-tree-inset')});
137
+ max-height: cv.getVar('tree-select-panel-max-height');
138
+ overflow-y: auto;
139
+ padding: cv.getVar('tree-select-tree-inset');
140
+ }
141
+ }
142
+
143
+ .#{iv.$class-prefix}tree-select-empty {
144
+ color: cv.getVar('tree-select-empty-color');
145
+ padding: cv.getVar('tree-select-empty-padding');
146
+ }
@@ -0,0 +1,306 @@
1
+ // Bestax Extras - AppFrame Styles
2
+ // The frame an app's pages sit in: a header across the top, a nav column down
3
+ // the side, the page, an aside and a footer, laid out by a grid. The header
4
+ // and the column stick while the document scrolls. Bulma has no frame.
5
+ //
6
+ // Below the root's breakpoint the nav is a drawer instead: fixed to the
7
+ // inline-start edge, slid out and `visibility: hidden` until it opens, so a
8
+ // closed one is out of the Tab order and the accessibility tree before any
9
+ // script runs. The layout is all in here, with a media query per breakpoint
10
+ // class, so the server's markup lays out as the browser's does.
11
+
12
+ @use 'bulma/sass/utilities/initial-variables' as iv;
13
+ @use 'bulma/sass/utilities/css-variables' as cv;
14
+ @use 'bulma/sass/utilities/mixins' as mx;
15
+ @use '../variables' as *;
16
+ @use '../mixins' as *;
17
+
18
+ // How far down the nav column starts sticking, and how far an in-page link
19
+ // or a Tab scrolls clear of the sticky header. A header taller than Bulma's
20
+ // navbar sets it on `:root`.
21
+ $app-frame-header-height: cv.getVar('navbar-height') !default;
22
+ $app-frame-header-background: cv.getVar('scheme-main') !default;
23
+ $app-frame-nav-width: 16rem !default;
24
+ $app-frame-nav-padding: 0.75rem !default;
25
+ $app-frame-nav-background: cv.getVar('scheme-main') !default;
26
+ $app-frame-aside-width: 20rem !default;
27
+ $app-frame-border-color: cv.getVar('border') !default;
28
+ $app-frame-border-width: 1px !default;
29
+ // The modal background's color: the inverted scheme at 0.86 alpha.
30
+ $app-frame-backdrop-background: hsla(
31
+ #{cv.getVar('scheme-h')},
32
+ #{cv.getVar('scheme-s')},
33
+ #{cv.getVar('scheme-invert-l')},
34
+ 0.86
35
+ ) !default;
36
+ $app-frame-drawer-shadow: cv.getVar('shadow') !default;
37
+ $app-frame-transition-duration: cv.getVar('duration') !default;
38
+ $app-frame-skip-link-background: cv.getVar('scheme-main') !default;
39
+ $app-frame-skip-link-color: cv.getVar('link') !default;
40
+
41
+ // The drawer leaves this much of the window showing beside it, so there's
42
+ // backdrop to press.
43
+ $-drawer-gap: 3rem;
44
+
45
+ // On Bulma's variables host, as `--bulma-navbar-height` is, so the document
46
+ // can read it for `scroll-padding-top`.
47
+ #{iv.$variables-host} {
48
+ @include cv.register-vars(
49
+ (
50
+ 'app-frame-header-height': #{$app-frame-header-height},
51
+ )
52
+ );
53
+ }
54
+
55
+ .#{iv.$class-prefix}app-frame {
56
+ @include cv.register-vars(
57
+ (
58
+ 'app-frame-header-background': #{$app-frame-header-background},
59
+ 'app-frame-nav-width': #{$app-frame-nav-width},
60
+ 'app-frame-nav-padding': #{$app-frame-nav-padding},
61
+ 'app-frame-nav-background': #{$app-frame-nav-background},
62
+ 'app-frame-aside-width': #{$app-frame-aside-width},
63
+ 'app-frame-border-color': #{$app-frame-border-color},
64
+ 'app-frame-border-width': #{$app-frame-border-width},
65
+ 'app-frame-backdrop-background': #{$app-frame-backdrop-background},
66
+ 'app-frame-drawer-shadow': #{$app-frame-drawer-shadow},
67
+ 'app-frame-transition-duration': #{$app-frame-transition-duration},
68
+ 'app-frame-skip-link-background': #{$app-frame-skip-link-background},
69
+ 'app-frame-skip-link-color': #{$app-frame-skip-link-color},
70
+ )
71
+ );
72
+ }
73
+
74
+ // An in-page link or a Tab lands below the sticky header (WCAG technique C43).
75
+ html:has(.#{iv.$class-prefix}app-frame) {
76
+ scroll-padding-top: cv.getVar('app-frame-header-height');
77
+ }
78
+
79
+ // ---- The grid, below the breakpoint ----------------------------------------------
80
+
81
+ // One column: the header, the page, the aside under it, and the footer. A
82
+ // part that isn't there leaves an empty `auto` row, which takes no room.
83
+ .#{iv.$class-prefix}app-frame {
84
+ display: grid;
85
+ grid-template-columns: minmax(0, 1fr);
86
+ grid-template-rows: auto 1fr auto auto;
87
+ grid-template-areas: 'header' 'main' 'aside' 'footer';
88
+ min-height: 100vh;
89
+ min-height: 100dvh;
90
+ }
91
+
92
+ .#{iv.$class-prefix}app-frame-header {
93
+ grid-area: header;
94
+ position: sticky;
95
+ inset-block-start: 0;
96
+ z-index: $extras-z-index-sticky;
97
+ background-color: cv.getVar('app-frame-header-background');
98
+ }
99
+
100
+ .#{iv.$class-prefix}app-frame-main {
101
+ grid-area: main;
102
+ min-width: 0;
103
+
104
+ // Focus lands here from the skip link, to start the Tab order there. It's
105
+ // not a control, so it draws no ring.
106
+ &:focus {
107
+ outline: none;
108
+ }
109
+ }
110
+
111
+ .#{iv.$class-prefix}app-frame-aside {
112
+ grid-area: aside;
113
+ min-width: 0;
114
+ }
115
+
116
+ .#{iv.$class-prefix}app-frame-footer {
117
+ grid-area: footer;
118
+ min-width: 0;
119
+ }
120
+
121
+ // The drawer: over everything, header included, from the inline-start edge.
122
+ // It slides out and hides once the slide is over, and shows at once as it
123
+ // opens, so focus can move in straight away.
124
+ .#{iv.$class-prefix}app-frame-nav {
125
+ position: fixed;
126
+ inset-block: 0;
127
+ inset-inline-start: 0;
128
+ z-index: $extras-z-index-fixed;
129
+ inline-size: min(
130
+ #{cv.getVar('app-frame-nav-width')},
131
+ calc(100vw - #{$-drawer-gap})
132
+ );
133
+ overflow-y: auto;
134
+ overscroll-behavior: contain;
135
+ padding: cv.getVar('app-frame-nav-padding');
136
+ background-color: cv.getVar('app-frame-nav-background');
137
+ box-shadow: cv.getVar('app-frame-drawer-shadow');
138
+ transform: translateX(-100%);
139
+ visibility: hidden;
140
+ transition-property: transform, visibility;
141
+ transition-duration: cv.getVar('app-frame-transition-duration'), 0s;
142
+ transition-delay: 0s, cv.getVar('app-frame-transition-duration');
143
+ transition-timing-function: $extras-easing;
144
+
145
+ &:dir(rtl) {
146
+ transform: translateX(100%);
147
+ }
148
+ }
149
+
150
+ // The open drawer is Bulma's active state, on the nav as on a navbar's menu.
151
+ .#{iv.$class-prefix}app-frame
152
+ > .#{iv.$class-prefix}app-frame-nav.#{iv.$class-prefix}is-active {
153
+ transform: none;
154
+ visibility: visible;
155
+ transition-delay: 0s;
156
+ }
157
+
158
+ // The close button, at the top of the drawer on its far side. Bulma's
159
+ // `.delete` is inline, which an auto margin can't push, whichever loads last.
160
+ .#{iv.$class-prefix}app-frame-nav > .#{iv.$class-prefix}app-frame-close {
161
+ display: flex;
162
+ margin-inline-start: auto;
163
+ margin-block-end: 0.5rem;
164
+ }
165
+
166
+ .#{iv.$class-prefix}app-frame-backdrop {
167
+ position: fixed;
168
+ inset: 0;
169
+ z-index: $extras-z-index-fixed - 1;
170
+ background-color: cv.getVar('app-frame-backdrop-background');
171
+ opacity: 0;
172
+ visibility: hidden;
173
+ transition-property: opacity, visibility;
174
+ transition-duration: cv.getVar('app-frame-transition-duration'), 0s;
175
+ transition-delay: 0s, cv.getVar('app-frame-transition-duration');
176
+ transition-timing-function: $extras-easing;
177
+ }
178
+
179
+ .#{iv.$class-prefix}app-frame
180
+ > .#{iv.$class-prefix}app-frame-backdrop.#{iv.$class-prefix}is-active {
181
+ opacity: 1;
182
+ visibility: visible;
183
+ transition-delay: 0s;
184
+ }
185
+
186
+ // Bulma hides a navbar's burger from desktop up. The frame's shows at every
187
+ // width, since from the breakpoint up it collapses the column.
188
+ .#{iv.$class-prefix}navbar-burger.#{iv.$class-prefix}app-frame-burger {
189
+ display: inline-flex;
190
+ }
191
+
192
+ // Hidden until it has focus, then over the header's start. It shows at once,
193
+ // rather than fading its background in with Bulma's link transition, which
194
+ // leaves its text over the header's while it fades.
195
+ .#{iv.$class-prefix}app-frame-skip-link {
196
+ @include extras-sr-only;
197
+ transition: none;
198
+
199
+ &:focus {
200
+ position: fixed;
201
+ inset-block-start: 0.5rem;
202
+ inset-inline-start: 0.5rem;
203
+ z-index: $extras-z-index-fixed;
204
+ width: auto;
205
+ height: auto;
206
+ margin: 0;
207
+ padding: 0.5em 1em;
208
+ overflow: visible;
209
+ clip: auto;
210
+ white-space: normal;
211
+ border-radius: cv.getVar('radius');
212
+ background-color: cv.getVar('app-frame-skip-link-background');
213
+ color: cv.getVar('app-frame-skip-link-color');
214
+ box-shadow: cv.getVar('shadow');
215
+ @include extras-focus-outline;
216
+ }
217
+ }
218
+
219
+ // ---- From the breakpoint up ------------------------------------------------------
220
+
221
+ // Three columns, the nav's, the page's and the aside's, each as wide as what's
222
+ // in it, under the header. The footer sits under the page. The nav is a
223
+ // column that sticks under the header as tall as the window less the header,
224
+ // and collapsed it slides out past the inline-start edge as its column
225
+ // closes, then hides.
226
+ @mixin -wide {
227
+ grid-template-columns: auto minmax(0, 1fr) auto;
228
+ grid-template-rows: auto 1fr auto;
229
+ grid-template-areas:
230
+ 'header header header'
231
+ 'nav main aside'
232
+ 'nav footer aside';
233
+
234
+ > .#{iv.$class-prefix}app-frame-nav {
235
+ grid-area: nav;
236
+ position: sticky;
237
+ inset: auto;
238
+ inset-block-start: cv.getVar('app-frame-header-height');
239
+ z-index: auto;
240
+ align-self: start;
241
+ inline-size: cv.getVar('app-frame-nav-width');
242
+ block-size: calc(100vh - #{cv.getVar('app-frame-header-height')});
243
+ block-size: calc(100dvh - #{cv.getVar('app-frame-header-height')});
244
+ border-inline-end: cv.getVar('app-frame-border-width') solid
245
+ cv.getVar('app-frame-border-color');
246
+ box-shadow: none;
247
+ transform: none;
248
+ visibility: visible;
249
+ transition-property: margin-inline-start, visibility;
250
+ transition-delay: 0s;
251
+ }
252
+
253
+ &.#{iv.$class-prefix}is-nav-collapsed > .#{iv.$class-prefix}app-frame-nav {
254
+ margin-inline-start: calc(-1 * #{cv.getVar('app-frame-nav-width')});
255
+ visibility: hidden;
256
+ transition-delay: 0s, cv.getVar('app-frame-transition-duration');
257
+ }
258
+
259
+ > .#{iv.$class-prefix}app-frame-nav > .#{iv.$class-prefix}app-frame-close,
260
+ > .#{iv.$class-prefix}app-frame-backdrop {
261
+ display: none;
262
+ }
263
+
264
+ > .#{iv.$class-prefix}app-frame-aside {
265
+ inline-size: cv.getVar('app-frame-aside-width');
266
+ border-inline-start: cv.getVar('app-frame-border-width') solid
267
+ cv.getVar('app-frame-border-color');
268
+ }
269
+ }
270
+
271
+ @include mx.tablet {
272
+ .#{iv.$class-prefix}app-frame.#{iv.$class-prefix}is-tablet {
273
+ @include -wide;
274
+ }
275
+ }
276
+
277
+ @include mx.desktop {
278
+ .#{iv.$class-prefix}app-frame.#{iv.$class-prefix}is-desktop {
279
+ @include -wide;
280
+ }
281
+ }
282
+
283
+ @include mx.widescreen {
284
+ .#{iv.$class-prefix}app-frame.#{iv.$class-prefix}is-widescreen {
285
+ @include -wide;
286
+ }
287
+ }
288
+
289
+ // ---- Media ---------------------------------------------------------------------
290
+
291
+ // The drawer's shadow is dropped in forced colors, so its open edge gets a
292
+ // border, as the column has.
293
+ @media (forced-colors: active) {
294
+ .#{iv.$class-prefix}app-frame-nav {
295
+ border-inline-end: cv.getVar('app-frame-border-width') solid
296
+ cv.getVar('app-frame-border-color');
297
+ }
298
+ }
299
+
300
+ // No slide, collapse or fade: each state shows at once.
301
+ @media (prefers-reduced-motion: reduce) {
302
+ .#{iv.$class-prefix}app-frame-nav,
303
+ .#{iv.$class-prefix}app-frame-backdrop {
304
+ transition: none !important;
305
+ }
306
+ }
@@ -2,5 +2,6 @@
2
2
  // Import all layout partials here: extras that structure a page, as Bulma's
3
3
  // own layout does
4
4
 
5
+ @use 'appframe';
5
6
  @use 'splitter';
6
7
  @use 'stack';