@phila/phila-ui-switch 0.0.1-beta.2
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/README.md +93 -0
- package/dist/Switch.vue.d.ts +45 -0
- package/dist/Switch.vue.d.ts.map +1 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +75 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Switch Component
|
|
2
|
+
|
|
3
|
+
City of Philadelphia switch input component with TypeScript support.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @phila/phila-ui-switch
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```vue
|
|
14
|
+
<template>
|
|
15
|
+
<Switch v-model="isEnabled">Enable notifications</Switch>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script setup>
|
|
19
|
+
import { ref } from "vue";
|
|
20
|
+
import { Switch } from "@phila/phila-ui-switch";
|
|
21
|
+
|
|
22
|
+
const isEnabled = ref(false);
|
|
23
|
+
</script>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Props
|
|
27
|
+
|
|
28
|
+
| Prop | Type | Default | Description |
|
|
29
|
+
| ------------ | ----------------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
30
|
+
| `id` | `string` | `generateRandomId("switch-input")` | Unique identifier (uses [generateRandomId](https://github.com/CityOfPhiladelphia/phila-ui-4/tree/main/packages/core#generateRandomId) from core) |
|
|
31
|
+
| `modelValue` | `string \| number \| boolean` | `false` | Current value (v-model) |
|
|
32
|
+
| `value` | `string \| number \| boolean` | `true` | Value when checked |
|
|
33
|
+
| `offValue` | `string \| number \| boolean` | `false` | Value when unchecked |
|
|
34
|
+
| `disabled` | `boolean` | `false` | Disable the switch |
|
|
35
|
+
| `name` | `string` | `"switch-input"` | Input name attribute |
|
|
36
|
+
| `autofocus` | `boolean` | `false` | Auto-focus on mount |
|
|
37
|
+
| `ariaLabel` | `string` | `"Switch input"` | Screen reader label |
|
|
38
|
+
| `className` | `string` | `undefined` | Additional CSS classes |
|
|
39
|
+
|
|
40
|
+
## Events
|
|
41
|
+
|
|
42
|
+
| Event | Payload | Description |
|
|
43
|
+
| ------------------- | ---------------------------------------------------- | -------------- |
|
|
44
|
+
| `update:modelValue` | `(value: string \| number \| boolean)` | v-model update |
|
|
45
|
+
| `change` | `(value: string \| number \| boolean, event: Event)` | State change |
|
|
46
|
+
| `focus` | `(event: FocusEvent)` | Focus event |
|
|
47
|
+
| `blur` | `(event: FocusEvent)` | Blur event |
|
|
48
|
+
|
|
49
|
+
## Examples
|
|
50
|
+
|
|
51
|
+
### Custom Values
|
|
52
|
+
|
|
53
|
+
```vue
|
|
54
|
+
<Switch v-model="status" :value="'active'" :off-value="'inactive'">
|
|
55
|
+
Status: {{ status }}
|
|
56
|
+
</Switch>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Disabled
|
|
60
|
+
|
|
61
|
+
```vue
|
|
62
|
+
<Switch v-model="isEnabled" disabled>Disabled switch</Switch>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Development
|
|
66
|
+
|
|
67
|
+
### Install Dependencies
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pnpm install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Run Demo
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pnpm dev
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Build Library
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pnpm build
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Type Check
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pnpm type-check
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
MIT
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { SwitchProps } from './index';
|
|
2
|
+
declare function __VLS_template(): {
|
|
3
|
+
attrs: Partial<{}>;
|
|
4
|
+
slots: {
|
|
5
|
+
default?(_: {}): any;
|
|
6
|
+
};
|
|
7
|
+
refs: {
|
|
8
|
+
inputRef: HTMLInputElement;
|
|
9
|
+
};
|
|
10
|
+
rootEl: HTMLLabelElement;
|
|
11
|
+
};
|
|
12
|
+
type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
|
|
13
|
+
declare const __VLS_component: import('vue').DefineComponent<SwitchProps, {
|
|
14
|
+
focus: () => Promise<void>;
|
|
15
|
+
blur: () => Promise<void>;
|
|
16
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
17
|
+
"update:modelValue": (value: string | number | boolean) => any;
|
|
18
|
+
change: (value: string | number | boolean, event: Event) => any;
|
|
19
|
+
focus: (event: FocusEvent) => any;
|
|
20
|
+
blur: (event: FocusEvent) => any;
|
|
21
|
+
}, string, import('vue').PublicProps, Readonly<SwitchProps> & Readonly<{
|
|
22
|
+
"onUpdate:modelValue"?: ((value: string | number | boolean) => any) | undefined;
|
|
23
|
+
onChange?: ((value: string | number | boolean, event: Event) => any) | undefined;
|
|
24
|
+
onFocus?: ((event: FocusEvent) => any) | undefined;
|
|
25
|
+
onBlur?: ((event: FocusEvent) => any) | undefined;
|
|
26
|
+
}>, {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
modelValue: string | number | boolean;
|
|
30
|
+
disabled: boolean;
|
|
31
|
+
value: string | number | boolean;
|
|
32
|
+
offValue: string | number | boolean;
|
|
33
|
+
autofocus: boolean;
|
|
34
|
+
ariaLabel: string;
|
|
35
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
|
|
36
|
+
inputRef: HTMLInputElement;
|
|
37
|
+
}, HTMLLabelElement>;
|
|
38
|
+
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
|
|
39
|
+
export default _default;
|
|
40
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
41
|
+
new (): {
|
|
42
|
+
$slots: S;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=Switch.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Switch.vue.d.ts","sourceRoot":"","sources":["../src/Switch.vue"],"names":[],"mappings":"AAyMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AA6F3C,iBAAS,cAAc;WAgET,OAAO,IAA6B;;yBAXrB,GAAG;;;;;;EAgB/B;AAiBD,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAC9D,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;oBAWnB,CAAC;wBACkB,uBAAuB,CAAC,OAAO,eAAe,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAAnG,wBAAoG;AAapG,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IACxC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
|
package/dist/index.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.switch[data-v-752a1efa]{display:inline-flex;align-items:center;cursor:pointer;position:relative}.switch--disabled[data-v-752a1efa]{cursor:not-allowed;opacity:.6}.switch-input[data-v-752a1efa]{position:absolute;opacity:0;width:0;height:0;margin:0;padding:0;border:none;outline:none}.switch-track[data-v-752a1efa]{display:inline-block;position:relative;background:var(--Schemes-Surface-Container-Highest, #ababab);transition:background-color .2s ease;display:flex;width:2rem;height:1.125rem;padding:var(--scale-xxsmall, .125rem);justify-content:flex-end;align-items:center;border-radius:var(--Radius-scale-radius-xl, 2rem);box-sizing:border-box}.switch-thumb[data-v-752a1efa]{width:.875rem;height:.875rem;flex-shrink:0;background-color:var(--Schemes-On-Primary, #ffffff);border-radius:var(--Radius-scale-radius-xl, 2rem);box-sizing:border-box;position:absolute;top:50%;left:var(--scale-xxsmall, .125rem);transform:translateY(-50%);transition:transform .2s ease}.switch-label[data-v-752a1efa]{padding-left:var(--scale-small, .5rem);color:var(--Schemes-On-Surface, #000);font-family:var(--Body-Default-font-body-default-family, Montserrat);font-size:var(--Body-Default-font-body-default-size, 1rem);font-style:normal;font-weight:400;line-height:var(--Body-Default-font-body-default-lineheight, 1.5rem)}.switch--checked .switch-track[data-v-752a1efa]{background:var(--Schemes-Primary, #003282)}.switch--checked .switch-thumb[data-v-752a1efa]{transform:translateY(-50%) translate(calc(2rem - .875rem - var(--scale-xxsmall, .125rem) - var(--scale-xxsmall, .125rem)))}.switch-input:focus+.switch-track[data-v-752a1efa]{outline:2px solid var(--Schemes-Primary, #003282);outline-offset:2px}.switch--disabled .switch-track[data-v-752a1efa]{background:var(--Schemes-Surface-Container, #e2e2e2)}.switch--disabled .switch-thumb[data-v-752a1efa]{background-color:var(--Schemes-On-Inverse-Surface, #f1f1f1)}.switch--disabled .switch-label[data-v-752a1efa]{color:var(--Schemes-Surface-Container-Highest, #ababab)}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseProps } from '@phila/phila-ui-core';
|
|
2
|
+
export { default as Switch } from './Switch.vue';
|
|
3
|
+
export interface SwitchProps extends BaseProps {
|
|
4
|
+
id?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
modelValue?: string | number | boolean;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
value?: string | number | boolean;
|
|
9
|
+
offValue?: string | number | boolean;
|
|
10
|
+
autofocus?: boolean;
|
|
11
|
+
ariaLabel?: string;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,cAAc,CAAC;AAEjD,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});require('./index.css');const e=require("vue"),r=require("@phila/phila-ui-core"),v=["for"],w=["id","name","checked","disabled","autofocus","aria-label","aria-labelledby","value"],y=["id"],V=e.defineComponent({__name:"Switch",props:{id:{default:()=>r.generateRandomId("switch-input")},name:{default:"switch-input"},modelValue:{type:[String,Number,Boolean],default:!1},disabled:{type:Boolean,default:!1},value:{type:[String,Number,Boolean],default:!0},offValue:{type:[String,Number,Boolean],default:!1},autofocus:{type:Boolean,default:!1},ariaLabel:{default:"Switch input"},className:{}},emits:["update:modelValue","change","focus","blur"],setup(a,{expose:u,emit:c}){const t=a,o=c,n=e.ref(),s=e.computed(()=>typeof t.modelValue=="boolean"?t.modelValue:t.modelValue===t.value),f=e.computed(()=>s.value?t.value:t.offValue),m=l=>{const i=l.target.checked?t.value:t.offValue;o("update:modelValue",i),o("change",i,l)},b=l=>{o("focus",l)},h=l=>{o("blur",l)};u({focus:async()=>{await e.nextTick(),n.value?.focus()},blur:async()=>{await e.nextTick(),n.value?.blur()}});const p=e.computed(()=>r.cn("switch",s.value&&"switch--checked",t.disabled&&"switch--disabled",t.className));return(l,d)=>(e.openBlock(),e.createElementBlock("label",{class:e.normalizeClass(p.value),for:a.id},[e.createElementVNode("input",{id:a.id,ref_key:"inputRef",ref:n,name:a.name,type:"checkbox",checked:s.value,disabled:a.disabled,autofocus:a.autofocus,"aria-label":a.ariaLabel,"aria-labelledby":`${a.id}-label`,value:f.value,class:"switch-input",onChange:m,onFocus:b,onBlur:h},null,40,w),d[0]||(d[0]=e.createElementVNode("span",{class:"switch-track"},[e.createElementVNode("span",{class:"switch-thumb"})],-1)),e.createElementVNode("span",{id:`${a.id}-label`,class:"switch-label"},[e.renderSlot(l.$slots,"default",{},void 0,!0)],8,y)],10,v))}}),g=(a,u)=>{const c=a.__vccOpts||a;for(const[t,o]of u)c[t]=o;return c},k=g(V,[["__scopeId","data-v-752a1efa"]]);exports.Switch=k;
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { defineComponent as w, ref as y, computed as i, createElementBlock as g, openBlock as k, normalizeClass as V, createElementVNode as s, renderSlot as B, nextTick as f } from "vue";
|
|
2
|
+
import { generateRandomId as S, cn as N } from "@phila/phila-ui-core";
|
|
3
|
+
import './index.css';const x = ["for"], C = ["id", "name", "checked", "disabled", "autofocus", "aria-label", "aria-labelledby", "value"], R = ["id"], $ = /* @__PURE__ */ w({
|
|
4
|
+
__name: "Switch",
|
|
5
|
+
props: {
|
|
6
|
+
id: { default: () => S("switch-input") },
|
|
7
|
+
name: { default: "switch-input" },
|
|
8
|
+
modelValue: { type: [String, Number, Boolean], default: !1 },
|
|
9
|
+
disabled: { type: Boolean, default: !1 },
|
|
10
|
+
value: { type: [String, Number, Boolean], default: !0 },
|
|
11
|
+
offValue: { type: [String, Number, Boolean], default: !1 },
|
|
12
|
+
autofocus: { type: Boolean, default: !1 },
|
|
13
|
+
ariaLabel: { default: "Switch input" },
|
|
14
|
+
className: {}
|
|
15
|
+
},
|
|
16
|
+
emits: ["update:modelValue", "change", "focus", "blur"],
|
|
17
|
+
setup(e, { expose: u, emit: o }) {
|
|
18
|
+
const a = e, l = o, c = y(), n = i(() => typeof a.modelValue == "boolean" ? a.modelValue : a.modelValue === a.value), m = i(() => n.value ? a.value : a.offValue), b = (t) => {
|
|
19
|
+
const r = t.target.checked ? a.value : a.offValue;
|
|
20
|
+
l("update:modelValue", r), l("change", r, t);
|
|
21
|
+
}, h = (t) => {
|
|
22
|
+
l("focus", t);
|
|
23
|
+
}, p = (t) => {
|
|
24
|
+
l("blur", t);
|
|
25
|
+
};
|
|
26
|
+
u({
|
|
27
|
+
focus: async () => {
|
|
28
|
+
await f(), c.value?.focus();
|
|
29
|
+
},
|
|
30
|
+
blur: async () => {
|
|
31
|
+
await f(), c.value?.blur();
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
const v = i(() => N("switch", n.value && "switch--checked", a.disabled && "switch--disabled", a.className));
|
|
35
|
+
return (t, d) => (k(), g("label", {
|
|
36
|
+
class: V(v.value),
|
|
37
|
+
for: e.id
|
|
38
|
+
}, [
|
|
39
|
+
s("input", {
|
|
40
|
+
id: e.id,
|
|
41
|
+
ref_key: "inputRef",
|
|
42
|
+
ref: c,
|
|
43
|
+
name: e.name,
|
|
44
|
+
type: "checkbox",
|
|
45
|
+
checked: n.value,
|
|
46
|
+
disabled: e.disabled,
|
|
47
|
+
autofocus: e.autofocus,
|
|
48
|
+
"aria-label": e.ariaLabel,
|
|
49
|
+
"aria-labelledby": `${e.id}-label`,
|
|
50
|
+
value: m.value,
|
|
51
|
+
class: "switch-input",
|
|
52
|
+
onChange: b,
|
|
53
|
+
onFocus: h,
|
|
54
|
+
onBlur: p
|
|
55
|
+
}, null, 40, C),
|
|
56
|
+
d[0] || (d[0] = s("span", { class: "switch-track" }, [
|
|
57
|
+
s("span", { class: "switch-thumb" })
|
|
58
|
+
], -1)),
|
|
59
|
+
s("span", {
|
|
60
|
+
id: `${e.id}-label`,
|
|
61
|
+
class: "switch-label"
|
|
62
|
+
}, [
|
|
63
|
+
B(t.$slots, "default", {}, void 0, !0)
|
|
64
|
+
], 8, R)
|
|
65
|
+
], 10, x));
|
|
66
|
+
}
|
|
67
|
+
}), E = (e, u) => {
|
|
68
|
+
const o = e.__vccOpts || e;
|
|
69
|
+
for (const [a, l] of u)
|
|
70
|
+
o[a] = l;
|
|
71
|
+
return o;
|
|
72
|
+
}, O = /* @__PURE__ */ E($, [["__scopeId", "data-v-752a1efa"]]);
|
|
73
|
+
export {
|
|
74
|
+
O as Switch
|
|
75
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@phila/phila-ui-switch",
|
|
3
|
+
"version": "0.0.1-beta.2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "City of Philadelphia switch input component",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs",
|
|
13
|
+
"require": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"ui",
|
|
21
|
+
"switch",
|
|
22
|
+
"vue",
|
|
23
|
+
"component"
|
|
24
|
+
],
|
|
25
|
+
"author": "",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"vue": "^3.0.0"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@phila/phila-ui-core": "2.2.0-beta.2"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^24.0.0",
|
|
35
|
+
"@vitejs/plugin-vue": "^6.0.1",
|
|
36
|
+
"eslint": "^9.0.0",
|
|
37
|
+
"typescript": "^5.8.3",
|
|
38
|
+
"vite": "^7.0.6",
|
|
39
|
+
"vite-plugin-dts": "^4.5.4",
|
|
40
|
+
"vite-plugin-lib-inject-css": "^2.2.2"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "vite build",
|
|
44
|
+
"dev": "vite build --watch",
|
|
45
|
+
"lint": "eslint src --ext .ts,.tsx,.vue",
|
|
46
|
+
"lint:fix": "eslint src --ext .ts,.tsx,.vue --fix",
|
|
47
|
+
"type-check": "tsc --noEmit",
|
|
48
|
+
"clean": "rm -rf dist",
|
|
49
|
+
"format": "prettier --write .",
|
|
50
|
+
"format:check": "prettier --check ."
|
|
51
|
+
}
|
|
52
|
+
}
|