@startupjs-ui/modal 0.1.22 → 0.2.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [0.2.0-alpha.1](https://github.com/startupjs/startupjs-ui/compare/v0.2.0-alpha.0...v0.2.0-alpha.1) (2026-04-10)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **dialogs:** use 'alertdialog' role for confirm(), prompt(), alert() ([ae2989f](https://github.com/startupjs/startupjs-ui/commit/ae2989fd6cf7b19a189330b3a180226727efc3fe))
12
+
13
+
14
+
15
+
16
+
17
+ # [0.2.0-alpha.0](https://github.com/startupjs/startupjs-ui/compare/v0.1.22...v0.2.0-alpha.0) (2026-03-27)
18
+
19
+
20
+ ### Features
21
+
22
+ * fix and improve accessibility of various components. Add storybook with tests. ([#21](https://github.com/startupjs/startupjs-ui/issues/21)) ([83b6576](https://github.com/startupjs/startupjs-ui/commit/83b65767ed61b24209f71b143ba1c2986170ab58))
23
+
24
+
25
+
26
+
27
+
6
28
  ## [0.1.22](https://github.com/startupjs/startupjs-ui/compare/v0.1.21...v0.1.22) (2026-03-25)
7
29
 
8
30
  **Note:** Version bump only for package @startupjs-ui/modal
@@ -18,3 +18,14 @@ $gutter = $UI.gutters.m
18
18
 
19
19
  .icon
20
20
  color: var(--color-text-description)
21
+
22
+ .srOnly
23
+ position absolute
24
+ width 1px
25
+ height 1px
26
+ padding 0
27
+ margin -1px
28
+ overflow hidden
29
+ clip rect(0, 0, 0, 0)
30
+ white-space nowrap
31
+ border 0
@@ -21,6 +21,8 @@ export interface ModalHeaderProps {
21
21
  closeIcon?: object
22
22
  /** Style applied to the close icon */
23
23
  iconStyle?: StyleProp<ViewStyle>
24
+ /** Web-only title id for dialog naming */
25
+ titleId?: string
24
26
  }
25
27
 
26
28
  function ModalHeader ({
@@ -28,16 +30,18 @@ function ModalHeader ({
28
30
  children,
29
31
  onCrossPress, // @private
30
32
  closeIcon = faTimes,
31
- iconStyle
33
+ iconStyle,
34
+ titleId
32
35
  }: ModalHeaderProps): ReactNode {
33
36
  return pug`
34
37
  Div.root(row style=style styleName=children ? 'between' : 'right' vAlign='center')
35
38
  if typeof children === 'string'
36
- Span.title(numberOfLines=1)= children
39
+ Span.title(id=titleId numberOfLines=1)= children
37
40
  else
38
41
  = children
39
42
  if onCrossPress
40
43
  Div.close(onPress=onCrossPress)
44
+ Span.srOnly Close dialog
41
45
  Icon.icon(
42
46
  style=iconStyle
43
47
  icon=closeIcon
package/README.mdx CHANGED
@@ -160,6 +160,7 @@ The modal can automatically display action buttons at the bottom:
160
160
  | `$visible` | `any` | | Scoped model for two-way visibility binding |
161
161
  | `ref` | `RefObject` | | Imperative ref exposing `open()` and `close()` |
162
162
  | `title` | `string` | | Header title text |
163
+ | `role` | `string` | `'dialog'` | Accessible role for the modal surface on web |
163
164
  | `cancelLabel` | `string` | `'Cancel'` | Label for the cancel button |
164
165
  | `confirmLabel` | `string` | `'Confirm'` | Label for the confirm button |
165
166
  | `showCross` | `boolean` | `true` | Whether to show a close icon in the header |
package/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // DO NOT MODIFY THIS FILE - IT IS AUTOMATICALLY GENERATED ON COMMITS.
3
3
 
4
4
  import { type ReactNode, type ComponentType, type RefObject } from 'react';
5
- import { type StyleProp, type ViewStyle } from 'react-native';
5
+ import { type StyleProp, type ViewStyle, type ViewProps } from 'react-native';
6
6
  type SupportedOrientation = 'portrait' | 'portrait-upside-down' | 'landscape' | 'landscape-left' | 'landscape-right';
7
7
  export declare const _PropsJsonSchema: {};
8
8
  export interface ModalProps {
@@ -22,6 +22,8 @@ export interface ModalProps {
22
22
  ref?: RefObject<any>;
23
23
  /** Header title text */
24
24
  title?: string;
25
+ /** Accessible role for the modal surface on web @default 'dialog' */
26
+ role?: ViewProps['role'];
25
27
  /** Label for cancel action @default 'Cancel' */
26
28
  cancelLabel?: string;
27
29
  /** Label for confirm action @default 'Confirm' */
package/index.tsx CHANGED
@@ -5,7 +5,7 @@ import React, {
5
5
  type ComponentType,
6
6
  type RefObject
7
7
  } from 'react'
8
- import { SafeAreaView, Modal as RNModal, type StyleProp, type ViewStyle } from 'react-native'
8
+ import { SafeAreaView, Modal as RNModal, type StyleProp, type ViewStyle, type ViewProps } from 'react-native'
9
9
  import { pug, observer, $ } from 'startupjs'
10
10
  import { themed } from '@startupjs-ui/core'
11
11
  import Portal from '@startupjs-ui/portal'
@@ -48,6 +48,8 @@ export interface ModalProps {
48
48
  ref?: RefObject<any>
49
49
  /** Header title text */
50
50
  title?: string
51
+ /** Accessible role for the modal surface on web @default 'dialog' */
52
+ role?: ViewProps['role']
51
53
  /** Label for cancel action @default 'Cancel' */
52
54
  cancelLabel?: string
53
55
  /** Label for confirm action @default 'Confirm' */
@@ -95,6 +97,7 @@ function ModalRoot ({
95
97
  $visible,
96
98
  ref,
97
99
  title,
100
+ role,
98
101
  cancelLabel = DEFAULT_CANCEL_LABEL,
99
102
  confirmLabel = DEFAULT_CONFIRM_LABEL,
100
103
  showCross = true,
@@ -175,6 +178,7 @@ function ModalRoot ({
175
178
  modalStyle=modalStyle
176
179
  variant=variant
177
180
  title=title
181
+ role=role
178
182
  cancelLabel=cancelLabel
179
183
  confirmLabel=confirmLabel
180
184
  showCross=showCross
package/layout.tsx CHANGED
@@ -1,5 +1,5 @@
1
- import React, { type ReactNode, type ComponentType } from 'react'
2
- import { View, TouchableOpacity, type StyleProp, type ViewStyle } from 'react-native'
1
+ import React, { useId, type ReactNode, type ComponentType } from 'react'
2
+ import { View, TouchableOpacity, type StyleProp, type ViewStyle, type ViewProps } from 'react-native'
3
3
  import { pug, observer } from 'startupjs'
4
4
  import { themed } from '@startupjs-ui/core'
5
5
  import ModalHeader from './ModalHeader'
@@ -18,6 +18,8 @@ export interface ModalLayoutProps {
18
18
  variant?: 'window' | 'fullscreen'
19
19
  /** Title rendered when no custom header provided */
20
20
  title?: string
21
+ /** Accessible role for the modal surface on web @default 'dialog' */
22
+ role?: ViewProps['role']
21
23
  /** DEPRECATED: use cancelLabel instead */
22
24
  dismissLabel?: string
23
25
  /** Cancel action label @default 'Cancel' */
@@ -48,6 +50,7 @@ function Modal ({
48
50
  children,
49
51
  variant,
50
52
  title,
53
+ role,
51
54
  dismissLabel,
52
55
  cancelLabel = DEFAULT_CANCEL_LABEL,
53
56
  confirmLabel = DEFAULT_CONFIRM_LABEL,
@@ -105,6 +108,10 @@ function Modal ({
105
108
  const isWindowLayout = variant === 'window'
106
109
  const hasActions = !!onCancel || !!onConfirm
107
110
  const hasHeader = !!title || !!showCross
111
+ const headerTitle = !title && React.isValidElement(header) && typeof (header as any).props?.children === 'string'
112
+ ? (header as any).props.children as string
113
+ : undefined
114
+ const dialogTitle = title ?? headerTitle
108
115
 
109
116
  const _onCrossPress = async (event: any) => {
110
117
  event.persist() // TODO: remove in react 17
@@ -146,9 +153,13 @@ function Modal ({
146
153
  cancelLabel = 'OK'
147
154
  }
148
155
 
156
+ const modalTitleId = useId()
157
+ const titleId = dialogTitle ? modalTitleId : undefined
158
+
149
159
  // Handle <Modal.Header>
150
160
  const headerProps = {
151
- onCrossPress: showCross ? _onCrossPress : undefined
161
+ onCrossPress: showCross ? _onCrossPress : undefined,
162
+ titleId
152
163
  }
153
164
 
154
165
  header = header
@@ -185,7 +196,10 @@ function Modal ({
185
196
  : React.createElement(ModalContent, contentProps, contentChildren)
186
197
 
187
198
  return pug`
188
- View.root(style=style styleName=[variant])
199
+ View.root(
200
+ style=style
201
+ styleName=[variant]
202
+ )
189
203
  if isWindowLayout
190
204
  TouchableOpacity.overlay(
191
205
  activeOpacity=1
@@ -194,6 +208,10 @@ function Modal ({
194
208
  ModalElement.modal(
195
209
  style=modalStyle
196
210
  styleName=[variant]
211
+ role=role ?? 'dialog'
212
+ aria-modal
213
+ aria-label=titleId ? undefined : dialogTitle
214
+ aria-labelledby=titleId
197
215
  )
198
216
  = header
199
217
  = content
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@startupjs-ui/modal",
3
- "version": "0.1.22",
3
+ "version": "0.2.0-alpha.1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -8,18 +8,18 @@
8
8
  "types": "index.d.ts",
9
9
  "type": "module",
10
10
  "dependencies": {
11
- "@startupjs-ui/button": "^0.1.22",
12
- "@startupjs-ui/core": "^0.1.22",
13
- "@startupjs-ui/div": "^0.1.22",
14
- "@startupjs-ui/icon": "^0.1.22",
15
- "@startupjs-ui/portal": "^0.1.22",
16
- "@startupjs-ui/scroll-view": "^0.1.22",
17
- "@startupjs-ui/span": "^0.1.22"
11
+ "@startupjs-ui/button": "^0.2.0-alpha.1",
12
+ "@startupjs-ui/core": "^0.2.0-alpha.1",
13
+ "@startupjs-ui/div": "^0.2.0-alpha.1",
14
+ "@startupjs-ui/icon": "^0.2.0-alpha.1",
15
+ "@startupjs-ui/portal": "^0.2.0-alpha.1",
16
+ "@startupjs-ui/scroll-view": "^0.2.0-alpha.1",
17
+ "@startupjs-ui/span": "^0.2.0-alpha.1"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "react": "*",
21
21
  "react-native": "*",
22
22
  "startupjs": "*"
23
23
  },
24
- "gitHead": "3bd18c16f0f203ee3d940bf2e09381edc0034665"
24
+ "gitHead": "b48004779559b16c96a2a1995dab13b998eafce9"
25
25
  }